bitwrench 2.0.16 → 2.0.18
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/README.md +127 -38
- package/dist/bitwrench-bccl.cjs.js +13 -9
- package/dist/bitwrench-bccl.cjs.min.js +2 -2
- package/dist/bitwrench-bccl.esm.js +13 -9
- package/dist/bitwrench-bccl.esm.min.js +2 -2
- package/dist/bitwrench-bccl.umd.js +13 -9
- package/dist/bitwrench-bccl.umd.min.js +2 -2
- package/dist/bitwrench-code-edit.cjs.js +1 -1
- package/dist/bitwrench-code-edit.cjs.min.js +1 -1
- package/dist/bitwrench-code-edit.es5.js +1 -1
- package/dist/bitwrench-code-edit.es5.min.js +1 -1
- package/dist/bitwrench-code-edit.esm.js +1 -1
- package/dist/bitwrench-code-edit.esm.min.js +1 -1
- package/dist/bitwrench-code-edit.umd.js +1 -1
- package/dist/bitwrench-code-edit.umd.min.js +1 -1
- package/dist/bitwrench-lean.cjs.js +1438 -920
- package/dist/bitwrench-lean.cjs.min.js +20 -20
- package/dist/bitwrench-lean.es5.js +1518 -1105
- package/dist/bitwrench-lean.es5.min.js +18 -18
- package/dist/bitwrench-lean.esm.js +1437 -920
- package/dist/bitwrench-lean.esm.min.js +20 -20
- package/dist/bitwrench-lean.umd.js +1438 -920
- package/dist/bitwrench-lean.umd.min.js +20 -20
- package/dist/bitwrench-util-css.cjs.js +236 -0
- package/dist/bitwrench-util-css.cjs.min.js +22 -0
- package/dist/bitwrench-util-css.es5.js +414 -0
- package/dist/bitwrench-util-css.es5.min.js +21 -0
- package/dist/bitwrench-util-css.esm.js +230 -0
- package/dist/bitwrench-util-css.esm.min.js +21 -0
- package/dist/bitwrench-util-css.umd.js +242 -0
- package/dist/bitwrench-util-css.umd.min.js +21 -0
- package/dist/bitwrench.cjs.js +1450 -928
- package/dist/bitwrench.cjs.min.js +21 -21
- package/dist/bitwrench.css +456 -132
- package/dist/bitwrench.es5.js +1563 -1140
- package/dist/bitwrench.es5.min.js +19 -19
- package/dist/bitwrench.esm.js +1450 -929
- package/dist/bitwrench.esm.min.js +21 -21
- package/dist/bitwrench.min.css +1 -1
- package/dist/bitwrench.umd.js +1450 -928
- package/dist/bitwrench.umd.min.js +21 -21
- package/dist/builds.json +178 -90
- package/dist/bwserve.cjs.js +528 -68
- package/dist/bwserve.esm.js +527 -69
- package/dist/sri.json +44 -36
- package/package.json +5 -2
- package/readme.html +136 -49
- package/src/bitwrench-bccl.js +12 -8
- package/src/bitwrench-color-utils.js +31 -9
- package/src/bitwrench-esm-entry.js +11 -0
- package/src/bitwrench-styles.js +439 -232
- package/src/bitwrench-util-css.js +229 -0
- package/src/bitwrench.js +979 -630
- package/src/bwserve/attach.js +57 -0
- package/src/bwserve/bwclient.js +141 -0
- package/src/bwserve/bwshell.js +102 -0
- package/src/bwserve/client.js +151 -1
- package/src/bwserve/index.js +139 -29
- package/src/cli/attach.js +555 -0
- package/src/cli/convert.js +2 -5
- package/src/cli/index.js +7 -0
- package/src/cli/inject.js +1 -1
- package/src/cli/layout-default.js +47 -32
- package/src/cli/serve.js +6 -2
- package/src/generate-css.js +11 -4
- package/src/vendor/html2canvas.min.js +20 -0
- package/src/version.js +3 -3
- package/src/bwserve/shell.js +0 -103
package/dist/bitwrench.umd.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
/*! bitwrench v2.0.
|
|
1
|
+
/*! bitwrench v2.0.18 | 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
|
/**
|
|
9
10
|
* Auto-generated version file from package.json
|
|
10
11
|
* DO NOT EDIT DIRECTLY - Use npm run generate-version
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
const VERSION_INFO = {
|
|
14
|
-
version: '2.0.
|
|
15
|
+
version: '2.0.18',
|
|
15
16
|
name: 'bitwrench',
|
|
16
17
|
description: 'A library for javascript UI functions.',
|
|
17
18
|
license: 'BSD-2-Clause',
|
|
18
19
|
homepage: 'https://deftio.github.com/bitwrench/pages',
|
|
19
20
|
repository: 'git+https://github.com/deftio/bitwrench.git',
|
|
20
21
|
author: 'manu a. chatterjee <deftio@deftio.com> (https://deftio.com/)',
|
|
21
|
-
buildDate: '2026-03-
|
|
22
|
+
buildDate: '2026-03-17T00:50:09.505Z'
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
/**
|
|
@@ -312,13 +313,18 @@
|
|
|
312
313
|
*/
|
|
313
314
|
function deriveShades(hex) {
|
|
314
315
|
var rgb = colorParse(hex);
|
|
316
|
+
// For light input colors (L > 75), mixing toward white produces invisible borders.
|
|
317
|
+
// Darken instead so borders remain visible against light backgrounds.
|
|
318
|
+
var borderColor = hexToHsl(hex)[2] > 75
|
|
319
|
+
? adjustLightness(hex, -18)
|
|
320
|
+
: mixColor(hex, '#ffffff', 0.60);
|
|
315
321
|
return {
|
|
316
322
|
base: hex,
|
|
317
323
|
hover: adjustLightness(hex, -10),
|
|
318
324
|
active: adjustLightness(hex, -15),
|
|
319
325
|
light: mixColor(hex, '#ffffff', 0.85),
|
|
320
326
|
darkText: adjustLightness(hex, -40),
|
|
321
|
-
border:
|
|
327
|
+
border: borderColor,
|
|
322
328
|
focus: 'rgba(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ',0.25)',
|
|
323
329
|
textOn: textOnColor(hex)
|
|
324
330
|
};
|
|
@@ -377,19 +383,27 @@
|
|
|
377
383
|
alt.secondary = deriveAlternateSeed(config.secondary);
|
|
378
384
|
alt.tertiary = config.tertiary ? deriveAlternateSeed(config.tertiary) : alt.primary;
|
|
379
385
|
|
|
380
|
-
// Derive alternate surface colors from primary hue
|
|
386
|
+
// Derive alternate surface colors from primary hue.
|
|
387
|
+
// Check actual page surface brightness (not seed color brightness) to decide
|
|
388
|
+
// whether alternate should be dark or light. The page surface is what the
|
|
389
|
+
// user sees; seeds can be dark while the page is still light (default L=96).
|
|
381
390
|
var priHsl = hexToHsl(config.primary);
|
|
382
391
|
var h = priHsl[0];
|
|
383
|
-
var
|
|
392
|
+
var primarySurface = config.surface || hslToHex([h, 8, 96]);
|
|
393
|
+
var isLight = relativeLuminance(primarySurface) > 0.179;
|
|
384
394
|
|
|
385
395
|
if (isLight) {
|
|
386
|
-
//
|
|
396
|
+
// Page surface is light → alternate needs dark surfaces
|
|
387
397
|
alt.light = hslToHex([h, Math.min(priHsl[1], 15), 15]);
|
|
388
398
|
alt.dark = hslToHex([h, 5, 88]);
|
|
399
|
+
alt.surface = hslToHex([h, 12, 18]);
|
|
400
|
+
alt.background = hslToHex([h, 10, 14]);
|
|
389
401
|
} else {
|
|
390
|
-
//
|
|
402
|
+
// Page surface is dark → alternate needs light surfaces
|
|
391
403
|
alt.light = hslToHex([h, Math.min(priHsl[1], 10), 96]);
|
|
392
404
|
alt.dark = hslToHex([h, 10, 18]);
|
|
405
|
+
alt.surface = hslToHex([h, 8, 96]);
|
|
406
|
+
alt.background = hslToHex([h, 6, 98]);
|
|
393
407
|
}
|
|
394
408
|
|
|
395
409
|
// Semantic colors: harmonize toward primary, then invert for alternate
|
|
@@ -437,10 +451,18 @@
|
|
|
437
451
|
var darkBase = config.dark || hslToHex([h, 10, 13]);
|
|
438
452
|
|
|
439
453
|
// Background & surface tokens — tinted with primary hue for theme personality.
|
|
440
|
-
//
|
|
454
|
+
// Saturation high enough that the hue is visible (each theme feels distinct)
|
|
455
|
+
// but low enough to stay neutral and readable.
|
|
441
456
|
// User can override with config.background / config.surface.
|
|
442
|
-
var bgBase = config.background || hslToHex([h,
|
|
443
|
-
var surfBase = config.surface || hslToHex([h,
|
|
457
|
+
var bgBase = config.background || hslToHex([h, 22, 96]);
|
|
458
|
+
var surfBase = config.surface || hslToHex([h, 25, 94]);
|
|
459
|
+
|
|
460
|
+
// surfaceAlt: subtle background variant for striped rows, hover states, headers.
|
|
461
|
+
// Slightly lighter than surface in dark mode, slightly darker in light mode.
|
|
462
|
+
var surfHsl = hexToHsl(surfBase);
|
|
463
|
+
var surfAlt = surfHsl[2] <= 50
|
|
464
|
+
? hslToHex([surfHsl[0], surfHsl[1], Math.min(surfHsl[2] + 8, 100)])
|
|
465
|
+
: hslToHex([surfHsl[0], surfHsl[1], Math.max(surfHsl[2] - 3, 0)]);
|
|
444
466
|
|
|
445
467
|
var palette = {
|
|
446
468
|
primary: deriveShades(config.primary),
|
|
@@ -453,7 +475,8 @@
|
|
|
453
475
|
light: deriveShades(lightBase),
|
|
454
476
|
dark: deriveShades(darkBase),
|
|
455
477
|
background: bgBase,
|
|
456
|
-
surface: surfBase
|
|
478
|
+
surface: surfBase,
|
|
479
|
+
surfaceAlt: surfAlt
|
|
457
480
|
};
|
|
458
481
|
|
|
459
482
|
return palette;
|
|
@@ -500,10 +523,12 @@
|
|
|
500
523
|
5: '1.5rem', // 24px
|
|
501
524
|
6: '2rem'};
|
|
502
525
|
|
|
526
|
+
let _S=SPACING_SCALE;
|
|
527
|
+
|
|
503
528
|
var SPACING_PRESETS = {
|
|
504
|
-
compact: { btn:
|
|
505
|
-
normal: { btn:
|
|
506
|
-
spacious: { btn:
|
|
529
|
+
compact: { btn: _S[1] + ' ' + _S[3], card: _S[3] + ' ' + _S[4], alert: _S[2] + ' ' + _S[4], cell: _S[2] + ' ' + _S[3], input: _S[1] + ' ' + _S[3] },
|
|
530
|
+
normal: { btn: _S[2] + ' ' + _S[4], card: _S[5] + ' ' + _S[5], alert: _S[3] + ' ' + _S[5], cell: _S[3] + ' ' + _S[4], input: _S[2] + ' ' + _S[3] },
|
|
531
|
+
spacious: { btn: _S[3] + ' ' + _S[5], card: _S[6] + ' ' + _S[6], alert: _S[4] + ' ' + _S[5], cell: _S[4] + ' ' + _S[5], input: _S[3] + ' ' + _S[4] }
|
|
507
532
|
};
|
|
508
533
|
|
|
509
534
|
var RADIUS_PRESETS = {
|
|
@@ -615,20 +640,14 @@
|
|
|
615
640
|
* Built-in theme presets — named color combinations
|
|
616
641
|
* Each preset provides primary, secondary, and tertiary seed colors.
|
|
617
642
|
*/
|
|
618
|
-
var THEME_PRESETS =
|
|
619
|
-
teal
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
amber: { primary: '#d97706', secondary: '#fbbf24', tertiary: '#f59e0b' },
|
|
627
|
-
emerald: { primary: '#059669', secondary: '#6ee7b7', tertiary: '#34d399' },
|
|
628
|
-
nord: { primary: '#5e81ac', secondary: '#88c0d0', tertiary: '#81a1c1' },
|
|
629
|
-
coral: { primary: '#ef6461', secondary: '#4a7c7e', tertiary: '#e8a87c' },
|
|
630
|
-
midnight: { primary: '#1e3a5f', secondary: '#7c8db5', tertiary: '#3d5a80' }
|
|
631
|
-
};
|
|
643
|
+
var THEME_PRESETS = Object.fromEntries([
|
|
644
|
+
['teal','#006666','#6c757d','#006666'],['ocean','#0077b6','#90e0ef','#00b4d8'],
|
|
645
|
+
['sunset','#e76f51','#264653','#e9c46a'],['forest','#2d6a4f','#95d5b2','#52b788'],
|
|
646
|
+
['slate','#343a40','#adb5bd','#6c757d'],['rose','#e11d48','#fda4af','#fb7185'],
|
|
647
|
+
['indigo','#4f46e5','#a5b4fc','#818cf8'],['amber','#d97706','#fbbf24','#f59e0b'],
|
|
648
|
+
['emerald','#059669','#6ee7b7','#34d399'],['nord','#5e81ac','#88c0d0','#81a1c1'],
|
|
649
|
+
['coral','#ef6461','#4a7c7e','#e8a87c'],['midnight','#1e3a5f','#7c8db5','#3d5a80']
|
|
650
|
+
].map(function(e) { return [e[0], {primary:e[1],secondary:e[2],tertiary:e[3]}]; }));
|
|
632
651
|
|
|
633
652
|
/**
|
|
634
653
|
* Resolve layout config to spacing, radius, typeScale, elevation, and motion objects.
|
|
@@ -675,6 +694,7 @@
|
|
|
675
694
|
if (sel.includes(',')) return sel.split(',').map(function(s) { return '.' + name + ' ' + s.trim(); }).join(', ');
|
|
676
695
|
return '.' + name + ' ' + sel;
|
|
677
696
|
}
|
|
697
|
+
var _sx=scopeSelector;
|
|
678
698
|
|
|
679
699
|
// =========================================================================
|
|
680
700
|
// Themed CSS generators
|
|
@@ -683,12 +703,12 @@
|
|
|
683
703
|
function generateTypographyThemed(scope, palette, layout) {
|
|
684
704
|
var mot = layout.motion;
|
|
685
705
|
var rules = {};
|
|
686
|
-
rules[
|
|
706
|
+
rules[_sx(scope, 'a')] = {
|
|
687
707
|
'color': palette.primary.base,
|
|
688
708
|
'text-decoration': 'none',
|
|
689
709
|
'transition': 'color ' + mot.fast + ' ' + mot.easing
|
|
690
710
|
};
|
|
691
|
-
rules[
|
|
711
|
+
rules[_sx(scope, 'a:hover')] = {
|
|
692
712
|
'color': palette.primary.hover,
|
|
693
713
|
'text-decoration': 'underline'
|
|
694
714
|
};
|
|
@@ -701,11 +721,11 @@
|
|
|
701
721
|
var rd = layout.radius;
|
|
702
722
|
|
|
703
723
|
// Base button (only when scoped — unscoped uses defaultStyles)
|
|
704
|
-
rules[
|
|
724
|
+
rules[_sx(scope, '.bw_btn')] = {
|
|
705
725
|
'padding': sp.btn,
|
|
706
726
|
'border-radius': rd.btn
|
|
707
727
|
};
|
|
708
|
-
rules[
|
|
728
|
+
rules[_sx(scope, '.bw_btn:focus-visible')] = {
|
|
709
729
|
'outline': '2px solid currentColor',
|
|
710
730
|
'outline-offset': '2px',
|
|
711
731
|
'box-shadow': '0 0 0 3px ' + palette.primary.focus
|
|
@@ -714,12 +734,12 @@
|
|
|
714
734
|
// Variant colors handled by palette class on component root
|
|
715
735
|
|
|
716
736
|
// Size variants (structural, reuse layout radius)
|
|
717
|
-
rules[
|
|
737
|
+
rules[_sx(scope, '.bw_btn_lg')] = {
|
|
718
738
|
'padding': '0.625rem 1.5rem',
|
|
719
739
|
'font-size': '1rem',
|
|
720
740
|
'border-radius': rd.btn === '50rem' ? '50rem' : (parseInt(rd.btn) + 2) + 'px'
|
|
721
741
|
};
|
|
722
|
-
rules[
|
|
742
|
+
rules[_sx(scope, '.bw_btn_sm')] = {
|
|
723
743
|
'padding': '0.25rem 0.75rem',
|
|
724
744
|
'font-size': '0.8125rem',
|
|
725
745
|
'border-radius': rd.btn === '50rem' ? '50rem' : (Math.max(parseInt(rd.btn) - 1, 0)) + 'px'
|
|
@@ -733,7 +753,7 @@
|
|
|
733
753
|
var sp = layout.spacing;
|
|
734
754
|
var rd = layout.radius;
|
|
735
755
|
|
|
736
|
-
rules[
|
|
756
|
+
rules[_sx(scope, '.bw_alert')] = {
|
|
737
757
|
'padding': sp.alert,
|
|
738
758
|
'border-radius': rd.alert
|
|
739
759
|
};
|
|
@@ -752,36 +772,36 @@
|
|
|
752
772
|
|
|
753
773
|
var elev = layout.elevation;
|
|
754
774
|
var motion = layout.motion;
|
|
755
|
-
rules[
|
|
775
|
+
rules[_sx(scope, '.bw_card')] = {
|
|
756
776
|
'background-color': palette.surface || '#fff',
|
|
757
777
|
'border': '1px solid ' + palette.light.border,
|
|
758
778
|
'border-radius': rd.card,
|
|
759
779
|
'box-shadow': elev.sm,
|
|
760
780
|
'transition': 'box-shadow ' + motion.normal + ' ' + motion.easing + ', transform ' + motion.normal + ' ' + motion.easing
|
|
761
781
|
};
|
|
762
|
-
rules[
|
|
782
|
+
rules[_sx(scope, '.bw_card:hover')] = {
|
|
763
783
|
'box-shadow': elev.md
|
|
764
784
|
};
|
|
765
|
-
rules[
|
|
785
|
+
rules[_sx(scope, '.bw_card_hoverable:hover')] = {
|
|
766
786
|
'box-shadow': elev.lg
|
|
767
787
|
};
|
|
768
|
-
rules[
|
|
788
|
+
rules[_sx(scope, '.bw_card_body')] = {
|
|
769
789
|
'padding': sp.card
|
|
770
790
|
};
|
|
771
|
-
rules[
|
|
791
|
+
rules[_sx(scope, '.bw_card_header')] = {
|
|
772
792
|
'padding': sp.card.split(' ').map(function(v) { return (parseFloat(v) * 0.7).toFixed(3).replace(/\.?0+$/, '') + 'rem'; }).join(' '),
|
|
773
|
-
'background-color': palette.
|
|
793
|
+
'background-color': palette.surfaceAlt,
|
|
774
794
|
'border-bottom': '1px solid ' + palette.light.border
|
|
775
795
|
};
|
|
776
|
-
rules[
|
|
777
|
-
'background-color': palette.
|
|
796
|
+
rules[_sx(scope, '.bw_card_footer')] = {
|
|
797
|
+
'background-color': palette.surfaceAlt,
|
|
778
798
|
'border-top': '1px solid ' + palette.light.border,
|
|
779
799
|
'color': palette.secondary.base
|
|
780
800
|
};
|
|
781
|
-
rules[
|
|
801
|
+
rules[_sx(scope, '.bw_card_title')] = {
|
|
782
802
|
'color': palette.dark.base
|
|
783
803
|
};
|
|
784
|
-
rules[
|
|
804
|
+
rules[_sx(scope, '.bw_card_subtitle')] = {
|
|
785
805
|
'color': palette.secondary.base
|
|
786
806
|
};
|
|
787
807
|
|
|
@@ -795,55 +815,55 @@
|
|
|
795
815
|
var sp = layout.spacing;
|
|
796
816
|
var rd = layout.radius;
|
|
797
817
|
|
|
798
|
-
rules[
|
|
818
|
+
rules[_sx(scope, '.bw_form_control')] = {
|
|
799
819
|
'padding': sp.input,
|
|
800
820
|
'border-radius': rd.input,
|
|
801
821
|
'color': palette.dark.base,
|
|
802
822
|
'background-color': palette.surface || '#fff',
|
|
803
823
|
'border-color': palette.light.border
|
|
804
824
|
};
|
|
805
|
-
rules[
|
|
825
|
+
rules[_sx(scope, '.bw_form_control:focus')] = {
|
|
806
826
|
'border-color': palette.primary.border,
|
|
807
827
|
'outline': '2px solid ' + palette.primary.base,
|
|
808
828
|
'outline-offset': '-1px',
|
|
809
829
|
'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
|
|
810
830
|
};
|
|
811
|
-
rules[
|
|
831
|
+
rules[_sx(scope, '.bw_form_control::placeholder')] = {
|
|
812
832
|
'color': palette.secondary.base
|
|
813
833
|
};
|
|
814
|
-
rules[
|
|
834
|
+
rules[_sx(scope, '.bw_form_label')] = {
|
|
815
835
|
'color': palette.dark.base
|
|
816
836
|
};
|
|
817
|
-
rules[
|
|
837
|
+
rules[_sx(scope, '.bw_form_text')] = {
|
|
818
838
|
'color': palette.secondary.base
|
|
819
839
|
};
|
|
820
|
-
rules[
|
|
840
|
+
rules[_sx(scope, '.bw_form_check_input:checked')] = {
|
|
821
841
|
'background-color': palette.primary.base,
|
|
822
842
|
'border-color': palette.primary.base
|
|
823
843
|
};
|
|
824
|
-
rules[
|
|
844
|
+
rules[_sx(scope, '.bw_form_check_input:focus')] = {
|
|
825
845
|
'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
|
|
826
846
|
};
|
|
827
847
|
// Validation states
|
|
828
|
-
rules[
|
|
829
|
-
rules[
|
|
848
|
+
rules[_sx(scope, '.bw_form_control.bw_is_valid')] = { 'border-color': palette.success.base };
|
|
849
|
+
rules[_sx(scope, '.bw_form_control.bw_is_valid:focus')] = {
|
|
830
850
|
'border-color': palette.success.base,
|
|
831
851
|
'box-shadow': '0 0 0 0.2rem ' + palette.success.focus
|
|
832
852
|
};
|
|
833
|
-
rules[
|
|
834
|
-
rules[
|
|
853
|
+
rules[_sx(scope, '.bw_form_control.bw_is_invalid')] = { 'border-color': palette.danger.base };
|
|
854
|
+
rules[_sx(scope, '.bw_form_control.bw_is_invalid:focus')] = {
|
|
835
855
|
'border-color': palette.danger.base,
|
|
836
856
|
'box-shadow': '0 0 0 0.2rem ' + palette.danger.focus
|
|
837
857
|
};
|
|
838
858
|
// Form select
|
|
839
|
-
rules[
|
|
859
|
+
rules[_sx(scope, '.bw_form_select')] = {
|
|
840
860
|
'padding': sp.input,
|
|
841
861
|
'border-radius': rd.input,
|
|
842
862
|
'color': palette.dark.base,
|
|
843
863
|
'background-color': palette.surface || '#fff',
|
|
844
864
|
'border-color': palette.light.border
|
|
845
865
|
};
|
|
846
|
-
rules[
|
|
866
|
+
rules[_sx(scope, '.bw_form_select:focus')] = {
|
|
847
867
|
'border-color': palette.primary.border,
|
|
848
868
|
'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
|
|
849
869
|
};
|
|
@@ -851,43 +871,46 @@
|
|
|
851
871
|
return rules;
|
|
852
872
|
}
|
|
853
873
|
|
|
854
|
-
function generateNavigation(scope, palette) {
|
|
874
|
+
function generateNavigation(scope, palette, layout) {
|
|
855
875
|
var rules = {};
|
|
856
|
-
rules[
|
|
857
|
-
'background-color': palette.
|
|
876
|
+
rules[_sx(scope, '.bw_navbar')] = {
|
|
877
|
+
'background-color': palette.surfaceAlt,
|
|
858
878
|
'border-bottom-color': palette.light.border
|
|
859
879
|
};
|
|
860
|
-
rules[
|
|
880
|
+
rules[_sx(scope, '.bw_navbar_brand')] = {
|
|
861
881
|
'color': palette.dark.base
|
|
862
882
|
};
|
|
863
|
-
rules[
|
|
864
|
-
'color': palette.secondary.base
|
|
883
|
+
rules[_sx(scope, '.bw_navbar_nav .bw_nav_link')] = {
|
|
884
|
+
'color': palette.secondary.base,
|
|
885
|
+
'border-radius': layout.radius.btn
|
|
865
886
|
};
|
|
866
|
-
rules[
|
|
867
|
-
'color': palette.dark.base
|
|
887
|
+
rules[_sx(scope, '.bw_navbar_nav .bw_nav_link:hover')] = {
|
|
888
|
+
'color': palette.dark.base,
|
|
889
|
+
'background-color': palette.surfaceAlt
|
|
868
890
|
};
|
|
869
|
-
rules[
|
|
891
|
+
rules[_sx(scope, '.bw_navbar_nav .bw_nav_link.active')] = {
|
|
870
892
|
'color': palette.primary.base,
|
|
871
|
-
'background-color': palette.primary.focus
|
|
893
|
+
'background-color': palette.primary.focus,
|
|
894
|
+
'font-weight': '600'
|
|
872
895
|
};
|
|
873
|
-
rules[
|
|
896
|
+
rules[_sx(scope, '.bw_navbar_dark')] = {
|
|
874
897
|
'background-color': palette.dark.base,
|
|
875
898
|
'border-bottom-color': palette.dark.hover
|
|
876
899
|
};
|
|
877
|
-
rules[
|
|
900
|
+
rules[_sx(scope, '.bw_navbar_dark .bw_navbar_brand')] = {
|
|
878
901
|
'color': palette.light.base
|
|
879
902
|
};
|
|
880
|
-
rules[
|
|
881
|
-
'color':
|
|
903
|
+
rules[_sx(scope, '.bw_navbar_dark .bw_nav_link')] = {
|
|
904
|
+
'color': palette.light.border
|
|
882
905
|
};
|
|
883
|
-
rules[
|
|
884
|
-
'color':
|
|
906
|
+
rules[_sx(scope, '.bw_navbar_dark .bw_nav_link:hover')] = {
|
|
907
|
+
'color': palette.light.base
|
|
885
908
|
};
|
|
886
|
-
rules[
|
|
887
|
-
'color':
|
|
909
|
+
rules[_sx(scope, '.bw_navbar_dark .bw_nav_link.active')] = {
|
|
910
|
+
'color': palette.light.base,
|
|
888
911
|
'font-weight': '600'
|
|
889
912
|
};
|
|
890
|
-
rules[
|
|
913
|
+
rules[_sx(scope, '.bw_nav_pills .bw_nav_link.active')] = {
|
|
891
914
|
'color': palette.primary.textOn,
|
|
892
915
|
'background-color': palette.primary.base
|
|
893
916
|
};
|
|
@@ -898,49 +921,58 @@
|
|
|
898
921
|
var rules = {};
|
|
899
922
|
var sp = layout.spacing;
|
|
900
923
|
|
|
901
|
-
rules[
|
|
924
|
+
rules[_sx(scope, '.bw_table')] = {
|
|
902
925
|
'color': palette.dark.base,
|
|
903
926
|
'border-color': palette.light.border
|
|
904
927
|
};
|
|
905
|
-
rules[
|
|
928
|
+
rules[_sx(scope, '.bw_table > :not(caption) > * > *')] = {
|
|
906
929
|
'padding': sp.cell,
|
|
907
930
|
'border-bottom-color': palette.light.border
|
|
908
931
|
};
|
|
909
|
-
rules[
|
|
932
|
+
rules[_sx(scope, '.bw_table > thead > tr > *')] = {
|
|
910
933
|
'color': palette.secondary.base,
|
|
911
934
|
'border-bottom-color': palette.light.border,
|
|
912
|
-
'background-color': palette.
|
|
935
|
+
'background-color': palette.surfaceAlt
|
|
913
936
|
};
|
|
914
|
-
rules[
|
|
915
|
-
'background-color':
|
|
937
|
+
rules[_sx(scope, '.bw_table_striped > tbody > tr:nth-of-type(odd) > *')] = {
|
|
938
|
+
'background-color': palette.surfaceAlt
|
|
916
939
|
};
|
|
917
|
-
rules[
|
|
940
|
+
rules[_sx(scope, '.bw_table_hover > tbody > tr:hover > *')] = {
|
|
918
941
|
'background-color': palette.primary.focus
|
|
919
942
|
};
|
|
920
|
-
rules[
|
|
943
|
+
rules[_sx(scope, '.bw_table_selectable > tbody > tr')] = {
|
|
944
|
+
'cursor': 'pointer'
|
|
945
|
+
};
|
|
946
|
+
rules[_sx(scope, '.bw_table > tbody > tr.bw_table_row_selected > *')] = {
|
|
947
|
+
'background-color': palette.primary.light
|
|
948
|
+
};
|
|
949
|
+
rules[_sx(scope, '.bw_table_bordered')] = {
|
|
921
950
|
'border-color': palette.light.border
|
|
922
951
|
};
|
|
923
|
-
rules[
|
|
952
|
+
rules[_sx(scope, '.bw_table caption')] = {
|
|
924
953
|
'color': palette.secondary.base
|
|
925
954
|
};
|
|
926
955
|
|
|
927
956
|
return rules;
|
|
928
957
|
}
|
|
929
958
|
|
|
930
|
-
function generateTabs(scope, palette) {
|
|
931
|
-
var rules = {};
|
|
932
|
-
rules[
|
|
959
|
+
function generateTabs(scope, palette, layout) {
|
|
960
|
+
var rules = {}, mo = layout.motion;
|
|
961
|
+
rules[_sx(scope, '.bw_nav_tabs')] = {
|
|
933
962
|
'border-bottom-color': palette.light.border
|
|
934
963
|
};
|
|
935
|
-
rules[
|
|
936
|
-
'color': palette.secondary.base
|
|
964
|
+
rules[_sx(scope, '.bw_nav_link')] = {
|
|
965
|
+
'color': palette.secondary.base,
|
|
966
|
+
'transition': 'color ' + mo.fast + ' ' + mo.easing + ', border-color ' + mo.fast + ' ' + mo.easing + ', background-color ' + mo.fast + ' ' + mo.easing
|
|
937
967
|
};
|
|
938
|
-
rules[
|
|
968
|
+
rules[_sx(scope, '.bw_nav_tabs .bw_nav_link:hover')] = {
|
|
939
969
|
'color': palette.dark.base,
|
|
970
|
+
'background-color': palette.surfaceAlt,
|
|
940
971
|
'border-bottom-color': palette.light.border
|
|
941
972
|
};
|
|
942
|
-
rules[
|
|
973
|
+
rules[_sx(scope, '.bw_nav_tabs .bw_nav_link.active')] = {
|
|
943
974
|
'color': palette.primary.base,
|
|
975
|
+
'background-color': palette.primary.focus,
|
|
944
976
|
'border-bottom': '2px solid ' + palette.primary.base
|
|
945
977
|
};
|
|
946
978
|
return rules;
|
|
@@ -949,23 +981,25 @@
|
|
|
949
981
|
function generateListGroups(scope, palette, layout) {
|
|
950
982
|
var rules = {};
|
|
951
983
|
var sp = layout.spacing;
|
|
984
|
+
var mo = layout.motion;
|
|
952
985
|
|
|
953
|
-
rules[
|
|
986
|
+
rules[_sx(scope, '.bw_list_group_item')] = {
|
|
954
987
|
'padding': sp.cell,
|
|
955
988
|
'color': palette.dark.base,
|
|
956
989
|
'background-color': palette.surface || '#fff',
|
|
957
|
-
'border-color': palette.light.border
|
|
990
|
+
'border-color': palette.light.border,
|
|
991
|
+
'transition': 'color ' + mo.fast + ' ' + mo.easing + ', background-color ' + mo.fast + ' ' + mo.easing
|
|
958
992
|
};
|
|
959
|
-
rules[
|
|
960
|
-
'background-color': palette.
|
|
993
|
+
rules[_sx(scope, 'a.bw_list_group_item:hover')] = {
|
|
994
|
+
'background-color': palette.surfaceAlt,
|
|
961
995
|
'color': palette.dark.hover
|
|
962
996
|
};
|
|
963
|
-
rules[
|
|
997
|
+
rules[_sx(scope, '.bw_list_group_item.active')] = {
|
|
964
998
|
'color': palette.primary.textOn,
|
|
965
999
|
'background-color': palette.primary.base,
|
|
966
1000
|
'border-color': palette.primary.base
|
|
967
1001
|
};
|
|
968
|
-
rules[
|
|
1002
|
+
rules[_sx(scope, '.bw_list_group_item.disabled')] = {
|
|
969
1003
|
'color': palette.secondary.base,
|
|
970
1004
|
'background-color': palette.surface || '#fff'
|
|
971
1005
|
};
|
|
@@ -973,28 +1007,37 @@
|
|
|
973
1007
|
return rules;
|
|
974
1008
|
}
|
|
975
1009
|
|
|
976
|
-
function generatePagination(scope, palette) {
|
|
977
|
-
var rules = {};
|
|
978
|
-
rules[
|
|
1010
|
+
function generatePagination(scope, palette, layout) {
|
|
1011
|
+
var rules = {}, mo = layout.motion, rd = layout.radius;
|
|
1012
|
+
rules[_sx(scope, '.bw_page_item:first-child .bw_page_link')] = {
|
|
1013
|
+
'border-top-left-radius': rd.btn,
|
|
1014
|
+
'border-bottom-left-radius': rd.btn
|
|
1015
|
+
};
|
|
1016
|
+
rules[_sx(scope, '.bw_page_item:last-child .bw_page_link')] = {
|
|
1017
|
+
'border-top-right-radius': rd.btn,
|
|
1018
|
+
'border-bottom-right-radius': rd.btn
|
|
1019
|
+
};
|
|
1020
|
+
rules[_sx(scope, '.bw_page_link')] = {
|
|
979
1021
|
'color': palette.primary.base,
|
|
980
1022
|
'background-color': palette.surface || '#fff',
|
|
981
|
-
'border-color': palette.light.border
|
|
1023
|
+
'border-color': palette.light.border,
|
|
1024
|
+
'transition': 'color ' + mo.fast + ' ' + mo.easing + ', background-color ' + mo.fast + ' ' + mo.easing
|
|
982
1025
|
};
|
|
983
|
-
rules[
|
|
1026
|
+
rules[_sx(scope, '.bw_page_link:hover')] = {
|
|
984
1027
|
'color': palette.primary.hover,
|
|
985
|
-
'background-color': palette.
|
|
1028
|
+
'background-color': palette.surfaceAlt,
|
|
986
1029
|
'border-color': palette.light.border
|
|
987
1030
|
};
|
|
988
|
-
rules[
|
|
1031
|
+
rules[_sx(scope, '.bw_page_link:focus')] = {
|
|
989
1032
|
'outline': '2px solid ' + palette.primary.base,
|
|
990
1033
|
'outline-offset': '-2px'
|
|
991
1034
|
};
|
|
992
|
-
rules[
|
|
1035
|
+
rules[_sx(scope, '.bw_page_item.bw_active .bw_page_link')] = {
|
|
993
1036
|
'color': palette.primary.textOn,
|
|
994
1037
|
'background-color': palette.primary.base,
|
|
995
1038
|
'border-color': palette.primary.base
|
|
996
1039
|
};
|
|
997
|
-
rules[
|
|
1040
|
+
rules[_sx(scope, '.bw_page_item.bw_disabled .bw_page_link')] = {
|
|
998
1041
|
'color': palette.secondary.base,
|
|
999
1042
|
'background-color': palette.surface || '#fff',
|
|
1000
1043
|
'border-color': palette.light.border
|
|
@@ -1004,12 +1047,12 @@
|
|
|
1004
1047
|
|
|
1005
1048
|
function generateProgress(scope, palette) {
|
|
1006
1049
|
var rules = {};
|
|
1007
|
-
rules[
|
|
1008
|
-
'background-color': palette.
|
|
1050
|
+
rules[_sx(scope, '.bw_progress')] = {
|
|
1051
|
+
'background-color': palette.surfaceAlt,
|
|
1009
1052
|
'box-shadow': 'inset 0 1px 2px rgba(0,0,0,.1)'
|
|
1010
1053
|
};
|
|
1011
|
-
rules[
|
|
1012
|
-
'color':
|
|
1054
|
+
rules[_sx(scope, '.bw_progress_bar')] = {
|
|
1055
|
+
'color': palette.primary.textOn,
|
|
1013
1056
|
'background-color': palette.primary.base,
|
|
1014
1057
|
'box-shadow': 'inset 0 -1px 0 rgba(0,0,0,.15)'
|
|
1015
1058
|
};
|
|
@@ -1028,26 +1071,31 @@
|
|
|
1028
1071
|
'color': palette.dark.base,
|
|
1029
1072
|
'background-color': bg
|
|
1030
1073
|
};
|
|
1031
|
-
rules[
|
|
1032
|
-
// Also apply to the scope element itself so themes work on any container, not just body
|
|
1033
|
-
if (scope) {
|
|
1034
|
-
rules['.' + scope] = baseReset;
|
|
1035
|
-
}
|
|
1074
|
+
rules[_sx(scope, 'body')] = baseReset;
|
|
1036
1075
|
return rules;
|
|
1037
1076
|
}
|
|
1038
1077
|
|
|
1039
|
-
function generateBreadcrumbThemed(scope, palette) {
|
|
1040
|
-
var rules = {};
|
|
1041
|
-
rules[
|
|
1042
|
-
'color': palette.
|
|
1078
|
+
function generateBreadcrumbThemed(scope, palette, layout) {
|
|
1079
|
+
var rules = {}, mo = layout.motion;
|
|
1080
|
+
rules[_sx(scope, '.bw_breadcrumb')] = {
|
|
1081
|
+
'background-color': palette.surfaceAlt,
|
|
1082
|
+
'padding': '0.625rem 1rem',
|
|
1083
|
+
'border-radius': layout.radius.btn
|
|
1043
1084
|
};
|
|
1044
|
-
rules[
|
|
1085
|
+
rules[_sx(scope, '.bw_breadcrumb_item + .bw_breadcrumb_item::before')] = {
|
|
1045
1086
|
'color': palette.secondary.base
|
|
1046
1087
|
};
|
|
1047
|
-
rules[
|
|
1088
|
+
rules[_sx(scope, '.bw_breadcrumb_item a')] = {
|
|
1089
|
+
'color': palette.primary.base,
|
|
1090
|
+
'transition': 'color ' + mo.fast + ' ' + mo.easing
|
|
1091
|
+
};
|
|
1092
|
+
rules[_sx(scope, '.bw_breadcrumb_item a:hover')] = {
|
|
1048
1093
|
'color': palette.primary.hover,
|
|
1049
1094
|
'text-decoration': 'underline'
|
|
1050
1095
|
};
|
|
1096
|
+
rules[_sx(scope, '.bw_breadcrumb_item.active')] = {
|
|
1097
|
+
'color': palette.dark.base
|
|
1098
|
+
};
|
|
1051
1099
|
return rules;
|
|
1052
1100
|
}
|
|
1053
1101
|
|
|
@@ -1055,11 +1103,11 @@
|
|
|
1055
1103
|
|
|
1056
1104
|
function generateCloseButtonThemed(scope, palette) {
|
|
1057
1105
|
var rules = {};
|
|
1058
|
-
rules[
|
|
1106
|
+
rules[_sx(scope, '.bw_close')] = {
|
|
1059
1107
|
'color': palette.dark.base,
|
|
1060
1108
|
'opacity': '0.5'
|
|
1061
1109
|
};
|
|
1062
|
-
rules[
|
|
1110
|
+
rules[_sx(scope, '.bw_close:focus')] = {
|
|
1063
1111
|
'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
|
|
1064
1112
|
};
|
|
1065
1113
|
return rules;
|
|
@@ -1067,82 +1115,94 @@
|
|
|
1067
1115
|
|
|
1068
1116
|
function generateSectionsThemed(scope, palette) {
|
|
1069
1117
|
var rules = {};
|
|
1070
|
-
rules[
|
|
1118
|
+
rules[_sx(scope, '.bw_section_subtitle')] = {
|
|
1071
1119
|
'color': palette.secondary.base
|
|
1072
1120
|
};
|
|
1073
|
-
rules[
|
|
1121
|
+
rules[_sx(scope, '.bw_feature_description')] = {
|
|
1074
1122
|
'color': palette.secondary.base
|
|
1075
1123
|
};
|
|
1076
|
-
rules[
|
|
1124
|
+
rules[_sx(scope, '.bw_cta_description')] = {
|
|
1077
1125
|
'color': palette.secondary.base
|
|
1078
1126
|
};
|
|
1079
1127
|
return rules;
|
|
1080
1128
|
}
|
|
1081
1129
|
|
|
1082
|
-
function generateAccordionThemed(scope, palette) {
|
|
1130
|
+
function generateAccordionThemed(scope, palette, layout) {
|
|
1083
1131
|
var rules = {};
|
|
1084
|
-
|
|
1132
|
+
var rd = layout ? layout.radius : { card: '8px' };
|
|
1133
|
+
rules[_sx(scope, '.bw_accordion_item')] = {
|
|
1085
1134
|
'background-color': palette.surface || '#fff',
|
|
1086
1135
|
'border-color': palette.light.border
|
|
1087
1136
|
};
|
|
1088
|
-
rules[
|
|
1137
|
+
rules[_sx(scope, '.bw_accordion_item:first-child')] = {
|
|
1138
|
+
'border-top-left-radius': rd.card,
|
|
1139
|
+
'border-top-right-radius': rd.card
|
|
1140
|
+
};
|
|
1141
|
+
rules[_sx(scope, '.bw_accordion_item:last-child')] = {
|
|
1142
|
+
'border-bottom-left-radius': rd.card,
|
|
1143
|
+
'border-bottom-right-radius': rd.card
|
|
1144
|
+
};
|
|
1145
|
+
rules[_sx(scope, '.bw_accordion_button')] = {
|
|
1089
1146
|
'color': palette.dark.base
|
|
1090
1147
|
};
|
|
1091
|
-
rules[
|
|
1148
|
+
rules[_sx(scope, '.bw_accordion_button:not(.bw_collapsed)')] = {
|
|
1092
1149
|
'color': palette.primary.darkText,
|
|
1093
|
-
'background-color': palette.primary.light
|
|
1150
|
+
'background-color': palette.primary.light,
|
|
1151
|
+
'border-left': '3px solid ' + palette.primary.base
|
|
1094
1152
|
};
|
|
1095
|
-
rules[
|
|
1096
|
-
'background-color': palette.
|
|
1153
|
+
rules[_sx(scope, '.bw_accordion_button:hover')] = {
|
|
1154
|
+
'background-color': palette.surfaceAlt
|
|
1097
1155
|
};
|
|
1098
|
-
rules[
|
|
1099
|
-
'background-color': palette.primary.
|
|
1156
|
+
rules[_sx(scope, '.bw_accordion_button:not(.bw_collapsed):hover')] = {
|
|
1157
|
+
'background-color': palette.primary.base,
|
|
1158
|
+
'color': palette.primary.textOn
|
|
1100
1159
|
};
|
|
1101
|
-
rules[
|
|
1160
|
+
rules[_sx(scope, '.bw_accordion_button:focus-visible')] = {
|
|
1102
1161
|
'box-shadow': '0 0 0 0.2rem ' + palette.primary.focus
|
|
1103
1162
|
};
|
|
1104
|
-
rules[
|
|
1105
|
-
'border-top': '1px solid ' + palette.light.border
|
|
1163
|
+
rules[_sx(scope, '.bw_accordion_body')] = {
|
|
1164
|
+
'border-top': '1px solid ' + palette.light.border,
|
|
1165
|
+
'background-color': palette.surfaceAlt
|
|
1106
1166
|
};
|
|
1107
1167
|
return rules;
|
|
1108
1168
|
}
|
|
1109
1169
|
|
|
1110
1170
|
function generateCarouselThemed(scope, palette) {
|
|
1111
1171
|
var rules = {};
|
|
1112
|
-
rules[
|
|
1113
|
-
'background-color': palette.
|
|
1172
|
+
rules[_sx(scope, '.bw_carousel')] = {
|
|
1173
|
+
'background-color': palette.surfaceAlt
|
|
1114
1174
|
};
|
|
1115
|
-
rules[
|
|
1175
|
+
rules[_sx(scope, '.bw_carousel_indicator.active')] = {
|
|
1116
1176
|
'background-color': palette.primary.base
|
|
1117
1177
|
};
|
|
1118
|
-
rules[
|
|
1119
|
-
'background-color':
|
|
1120
|
-
'color':
|
|
1178
|
+
rules[_sx(scope, '.bw_carousel_control')] = {
|
|
1179
|
+
'background-color': palette.dark.base,
|
|
1180
|
+
'color': palette.dark.textOn
|
|
1121
1181
|
};
|
|
1122
|
-
rules[
|
|
1123
|
-
'background-color':
|
|
1182
|
+
rules[_sx(scope, '.bw_carousel_control:hover')] = {
|
|
1183
|
+
'background-color': palette.dark.hover
|
|
1124
1184
|
};
|
|
1125
|
-
rules[
|
|
1126
|
-
'background': 'linear-gradient(transparent,
|
|
1127
|
-
'color':
|
|
1185
|
+
rules[_sx(scope, '.bw_carousel_caption')] = {
|
|
1186
|
+
'background': 'linear-gradient(transparent, ' + palette.dark.base + ')',
|
|
1187
|
+
'color': palette.dark.textOn
|
|
1128
1188
|
};
|
|
1129
1189
|
return rules;
|
|
1130
1190
|
}
|
|
1131
1191
|
|
|
1132
1192
|
function generateModalThemed(scope, palette, layout) {
|
|
1133
1193
|
var rules = {};
|
|
1134
|
-
rules[
|
|
1194
|
+
rules[_sx(scope, '.bw_modal_content')] = {
|
|
1135
1195
|
'background-color': palette.surface || '#fff',
|
|
1136
1196
|
'border-color': palette.light.border,
|
|
1137
1197
|
'box-shadow': layout.elevation.lg
|
|
1138
1198
|
};
|
|
1139
|
-
rules[
|
|
1199
|
+
rules[_sx(scope, '.bw_modal_header')] = {
|
|
1140
1200
|
'border-bottom-color': palette.light.border
|
|
1141
1201
|
};
|
|
1142
|
-
rules[
|
|
1202
|
+
rules[_sx(scope, '.bw_modal_footer')] = {
|
|
1143
1203
|
'border-top-color': palette.light.border
|
|
1144
1204
|
};
|
|
1145
|
-
rules[
|
|
1205
|
+
rules[_sx(scope, '.bw_modal_title')] = {
|
|
1146
1206
|
'color': palette.dark.base
|
|
1147
1207
|
};
|
|
1148
1208
|
return rules;
|
|
@@ -1150,13 +1210,13 @@
|
|
|
1150
1210
|
|
|
1151
1211
|
function generateToastThemed(scope, palette, layout) {
|
|
1152
1212
|
var rules = {};
|
|
1153
|
-
rules[
|
|
1213
|
+
rules[_sx(scope, '.bw_toast')] = {
|
|
1154
1214
|
'background-color': palette.surface || '#fff',
|
|
1155
|
-
'border-color':
|
|
1215
|
+
'border-color': palette.light.border,
|
|
1156
1216
|
'box-shadow': layout.elevation.lg
|
|
1157
1217
|
};
|
|
1158
|
-
rules[
|
|
1159
|
-
'border-bottom-color':
|
|
1218
|
+
rules[_sx(scope, '.bw_toast_header')] = {
|
|
1219
|
+
'border-bottom-color': palette.light.border
|
|
1160
1220
|
};
|
|
1161
1221
|
// Variant toast borders handled by palette class
|
|
1162
1222
|
return rules;
|
|
@@ -1164,22 +1224,23 @@
|
|
|
1164
1224
|
|
|
1165
1225
|
function generateDropdownThemed(scope, palette, layout) {
|
|
1166
1226
|
var rules = {};
|
|
1167
|
-
rules[
|
|
1227
|
+
rules[_sx(scope, '.bw_dropdown_menu')] = {
|
|
1168
1228
|
'background-color': palette.surface || '#fff',
|
|
1169
1229
|
'border-color': palette.light.border,
|
|
1170
1230
|
'box-shadow': layout.elevation.md
|
|
1171
1231
|
};
|
|
1172
|
-
rules[
|
|
1173
|
-
'color': palette.dark.base
|
|
1232
|
+
rules[_sx(scope, '.bw_dropdown_item')] = {
|
|
1233
|
+
'color': palette.dark.base,
|
|
1234
|
+
'transition': 'background-color ' + layout.motion.fast + ' ' + layout.motion.easing
|
|
1174
1235
|
};
|
|
1175
|
-
rules[
|
|
1236
|
+
rules[_sx(scope, '.bw_dropdown_item:hover')] = {
|
|
1176
1237
|
'color': palette.dark.hover,
|
|
1177
|
-
'background-color': palette.
|
|
1238
|
+
'background-color': palette.surfaceAlt
|
|
1178
1239
|
};
|
|
1179
|
-
rules[
|
|
1240
|
+
rules[_sx(scope, '.bw_dropdown_item.disabled')] = {
|
|
1180
1241
|
'color': palette.secondary.base
|
|
1181
1242
|
};
|
|
1182
|
-
rules[
|
|
1243
|
+
rules[_sx(scope, '.bw_dropdown_divider')] = {
|
|
1183
1244
|
'border-top-color': palette.light.border
|
|
1184
1245
|
};
|
|
1185
1246
|
return rules;
|
|
@@ -1187,15 +1248,15 @@
|
|
|
1187
1248
|
|
|
1188
1249
|
function generateSwitchThemed(scope, palette) {
|
|
1189
1250
|
var rules = {};
|
|
1190
|
-
rules[
|
|
1251
|
+
rules[_sx(scope, '.bw_form_switch .bw_switch_input')] = {
|
|
1191
1252
|
'background-color': palette.secondary.base,
|
|
1192
1253
|
'border-color': palette.secondary.base
|
|
1193
1254
|
};
|
|
1194
|
-
rules[
|
|
1255
|
+
rules[_sx(scope, '.bw_form_switch .bw_switch_input:checked')] = {
|
|
1195
1256
|
'background-color': palette.primary.base,
|
|
1196
1257
|
'border-color': palette.primary.base
|
|
1197
1258
|
};
|
|
1198
|
-
rules[
|
|
1259
|
+
rules[_sx(scope, '.bw_form_switch .bw_switch_input:focus')] = {
|
|
1199
1260
|
'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
|
|
1200
1261
|
};
|
|
1201
1262
|
return rules;
|
|
@@ -1203,88 +1264,102 @@
|
|
|
1203
1264
|
|
|
1204
1265
|
function generateSkeletonThemed(scope, palette) {
|
|
1205
1266
|
var rules = {};
|
|
1206
|
-
rules[
|
|
1207
|
-
'background': 'linear-gradient(90deg, ' + palette.light.border + ' 25%, ' + palette.
|
|
1267
|
+
rules[_sx(scope, '.bw_skeleton')] = {
|
|
1268
|
+
'background': 'linear-gradient(90deg, ' + palette.light.border + ' 25%, ' + palette.surfaceAlt + ' 37%, ' + palette.light.border + ' 63%)'
|
|
1208
1269
|
};
|
|
1209
1270
|
return rules;
|
|
1210
1271
|
}
|
|
1211
1272
|
|
|
1212
1273
|
// generateAvatarThemed: removed — palette class on root handles variants
|
|
1213
1274
|
|
|
1214
|
-
function generateStatCardThemed(scope, palette) {
|
|
1215
|
-
var rules = {};
|
|
1275
|
+
function generateStatCardThemed(scope, palette, layout) {
|
|
1276
|
+
var rules = {}, mo = layout.motion, el = layout.elevation, rd = layout.radius;
|
|
1277
|
+
rules[_sx(scope, '.bw_stat_card')] = {
|
|
1278
|
+
'background-color': palette.surface || '#fff',
|
|
1279
|
+
'color': palette.dark.base,
|
|
1280
|
+
'border': '1px solid ' + palette.light.border,
|
|
1281
|
+
'border-radius': rd.card,
|
|
1282
|
+
'box-shadow': el.sm,
|
|
1283
|
+
'transition': 'box-shadow ' + mo.fast + ' ' + mo.easing + ', transform ' + mo.fast + ' ' + mo.easing
|
|
1284
|
+
};
|
|
1285
|
+
rules[_sx(scope, '.bw_stat_card:hover')] = { 'box-shadow': el.md };
|
|
1216
1286
|
// Variant border colors handled by palette class
|
|
1217
|
-
rules[
|
|
1218
|
-
rules[
|
|
1287
|
+
rules[_sx(scope, '.bw_stat_change_up')] = { 'color': palette.success.base };
|
|
1288
|
+
rules[_sx(scope, '.bw_stat_change_down')] = { 'color': palette.danger.base };
|
|
1219
1289
|
return rules;
|
|
1220
1290
|
}
|
|
1221
1291
|
|
|
1222
1292
|
function generateTimelineThemed(scope, palette) {
|
|
1223
1293
|
var rules = {};
|
|
1224
|
-
rules[
|
|
1294
|
+
rules[_sx(scope, '.bw_timeline::before')] = { 'background-color': palette.light.border };
|
|
1225
1295
|
// Variant marker colors handled by palette class
|
|
1226
|
-
rules[
|
|
1296
|
+
rules[_sx(scope, '.bw_timeline_date')] = { 'color': palette.secondary.base };
|
|
1227
1297
|
return rules;
|
|
1228
1298
|
}
|
|
1229
1299
|
|
|
1230
1300
|
function generateStepperThemed(scope, palette) {
|
|
1231
1301
|
var rules = {};
|
|
1232
|
-
rules[
|
|
1233
|
-
'background-color': palette.
|
|
1302
|
+
rules[_sx(scope, '.bw_step_indicator')] = {
|
|
1303
|
+
'background-color': palette.surfaceAlt,
|
|
1234
1304
|
'border': '2px solid ' + palette.light.border,
|
|
1235
1305
|
'color': palette.secondary.base
|
|
1236
1306
|
};
|
|
1237
|
-
rules[
|
|
1238
|
-
rules[
|
|
1307
|
+
rules[_sx(scope, '.bw_step + .bw_step::before')] = { 'background-color': palette.light.border };
|
|
1308
|
+
rules[_sx(scope, '.bw_step_active .bw_step_indicator')] = {
|
|
1239
1309
|
'background-color': palette.primary.base,
|
|
1240
1310
|
'color': palette.primary.textOn
|
|
1241
1311
|
};
|
|
1242
|
-
rules[
|
|
1312
|
+
rules[_sx(scope, '.bw_step_active .bw_step_label')] = {
|
|
1243
1313
|
'color': palette.dark.base,
|
|
1244
1314
|
'font-weight': '600'
|
|
1245
1315
|
};
|
|
1246
|
-
rules[
|
|
1316
|
+
rules[_sx(scope, '.bw_step_completed .bw_step_indicator')] = {
|
|
1247
1317
|
'background-color': palette.primary.base,
|
|
1248
1318
|
'color': palette.primary.textOn
|
|
1249
1319
|
};
|
|
1250
|
-
rules[
|
|
1251
|
-
rules[
|
|
1320
|
+
rules[_sx(scope, '.bw_step_completed .bw_step_label')] = { 'color': palette.primary.base };
|
|
1321
|
+
rules[_sx(scope, '.bw_step_completed + .bw_step::before')] = { 'background-color': palette.primary.base };
|
|
1252
1322
|
return rules;
|
|
1253
1323
|
}
|
|
1254
1324
|
|
|
1255
1325
|
function generateChipInputThemed(scope, palette) {
|
|
1256
1326
|
var rules = {};
|
|
1257
|
-
rules[
|
|
1258
|
-
|
|
1327
|
+
rules[_sx(scope, '.bw_chip_input')] = {
|
|
1328
|
+
'border-color': palette.light.border,
|
|
1329
|
+
'background-color': palette.surface || '#fff',
|
|
1330
|
+
'color': palette.dark.base
|
|
1331
|
+
};
|
|
1332
|
+
rules[_sx(scope, '.bw_chip_input:focus-within')] = {
|
|
1259
1333
|
'border-color': palette.primary.base,
|
|
1260
1334
|
'box-shadow': '0 0 0 0.2rem ' + palette.primary.focus
|
|
1261
1335
|
};
|
|
1262
|
-
rules[
|
|
1263
|
-
'background-color': palette.
|
|
1336
|
+
rules[_sx(scope, '.bw_chip')] = {
|
|
1337
|
+
'background-color': palette.surfaceAlt,
|
|
1264
1338
|
'color': palette.dark.base
|
|
1265
1339
|
};
|
|
1266
|
-
rules[
|
|
1340
|
+
rules[_sx(scope, '.bw_chip_remove:hover')] = {
|
|
1267
1341
|
'color': palette.danger.base,
|
|
1268
1342
|
'background-color': palette.danger.light
|
|
1269
1343
|
};
|
|
1270
1344
|
return rules;
|
|
1271
1345
|
}
|
|
1272
1346
|
|
|
1273
|
-
function generateFileUploadThemed(scope, palette) {
|
|
1274
|
-
var rules = {};
|
|
1275
|
-
rules[
|
|
1347
|
+
function generateFileUploadThemed(scope, palette, layout) {
|
|
1348
|
+
var rules = {}, mo = layout.motion;
|
|
1349
|
+
rules[_sx(scope, '.bw_file_upload')] = {
|
|
1276
1350
|
'border-color': palette.light.border,
|
|
1277
|
-
'background-color': palette.
|
|
1351
|
+
'background-color': palette.surfaceAlt,
|
|
1352
|
+
'transition': 'border-color ' + mo.fast + ' ' + mo.easing + ', background-color ' + mo.fast + ' ' + mo.easing
|
|
1278
1353
|
};
|
|
1279
|
-
rules[
|
|
1354
|
+
rules[_sx(scope, '.bw_file_upload:hover')] = {
|
|
1280
1355
|
'border-color': palette.primary.base,
|
|
1281
1356
|
'background-color': palette.primary.light
|
|
1282
1357
|
};
|
|
1283
|
-
rules[
|
|
1358
|
+
rules[_sx(scope, '.bw_file_upload:focus')] = {
|
|
1284
1359
|
'outline': '2px solid ' + palette.primary.base,
|
|
1285
1360
|
'outline-offset': '2px'
|
|
1286
1361
|
};
|
|
1287
|
-
rules[
|
|
1362
|
+
rules[_sx(scope, '.bw_file_upload.bw_file_upload_active')] = {
|
|
1288
1363
|
'border-color': palette.primary.base,
|
|
1289
1364
|
'background-color': palette.primary.light,
|
|
1290
1365
|
'border-style': 'solid'
|
|
@@ -1294,35 +1369,73 @@
|
|
|
1294
1369
|
|
|
1295
1370
|
function generateRangeThemed(scope, palette) {
|
|
1296
1371
|
var rules = {};
|
|
1297
|
-
rules[
|
|
1298
|
-
rules[
|
|
1372
|
+
rules[_sx(scope, '.bw_range')] = { 'background-color': palette.light.border };
|
|
1373
|
+
rules[_sx(scope, '.bw_range::-webkit-slider-thumb')] = {
|
|
1299
1374
|
'background-color': palette.primary.base,
|
|
1300
|
-
'border-color': '#fff',
|
|
1375
|
+
'border-color': palette.surface || '#fff',
|
|
1301
1376
|
'box-shadow': '0 1px 3px rgba(0,0,0,0.2)',
|
|
1302
1377
|
'transition': 'background-color 0.15s ease-out, transform 0.15s ease-out'
|
|
1303
1378
|
};
|
|
1304
|
-
rules[
|
|
1379
|
+
rules[_sx(scope, '.bw_range::-moz-range-thumb')] = {
|
|
1305
1380
|
'background-color': palette.primary.base,
|
|
1306
|
-
'border-color': '#fff',
|
|
1381
|
+
'border-color': palette.surface || '#fff',
|
|
1307
1382
|
'box-shadow': '0 1px 3px rgba(0,0,0,0.2)'
|
|
1308
1383
|
};
|
|
1309
1384
|
return rules;
|
|
1310
1385
|
}
|
|
1311
1386
|
|
|
1312
|
-
function
|
|
1313
|
-
var rules = {};
|
|
1314
|
-
rules[
|
|
1387
|
+
function generateTooltipThemed(scope, palette, layout) {
|
|
1388
|
+
var rules = {}, sp = layout.spacing, rd = layout.radius, el = layout.elevation, mo = layout.motion;
|
|
1389
|
+
rules[_sx(scope, '.bw_tooltip')] = {
|
|
1390
|
+
'background-color': palette.dark.base, 'color': palette.dark.textOn,
|
|
1391
|
+
'padding': sp.input, 'border-radius': rd.badge, 'box-shadow': el.md,
|
|
1392
|
+
'transition': 'opacity ' + mo.fast + ' ' + mo.easing + ', transform ' + mo.fast + ' ' + mo.easing
|
|
1393
|
+
};
|
|
1394
|
+
return rules;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
function generatePopoverThemed(scope, palette, layout) {
|
|
1398
|
+
var rules = {}, sp = layout.spacing, rd = layout.radius, el = layout.elevation, mo = layout.motion;
|
|
1399
|
+
rules[_sx(scope, '.bw_popover')] = {
|
|
1400
|
+
'background-color': palette.surface || '#fff', 'color': palette.dark.base,
|
|
1401
|
+
'border': '1px solid ' + palette.light.border, 'border-radius': rd.card, 'box-shadow': el.lg,
|
|
1402
|
+
'transition': 'opacity ' + mo.fast + ' ' + mo.easing + ', transform ' + mo.fast + ' ' + mo.easing
|
|
1403
|
+
};
|
|
1404
|
+
rules[_sx(scope, '.bw_popover_header')] = {
|
|
1405
|
+
'background-color': palette.surfaceAlt, 'border-bottom': '1px solid ' + palette.light.border,
|
|
1406
|
+
'padding': sp.input
|
|
1407
|
+
};
|
|
1408
|
+
rules[_sx(scope, '.bw_popover_body')] = { 'padding': sp.card };
|
|
1315
1409
|
return rules;
|
|
1316
1410
|
}
|
|
1317
1411
|
|
|
1318
|
-
function
|
|
1412
|
+
function generateSearchThemed(scope, palette, layout) {
|
|
1413
|
+
var rules = {}, mo = layout.motion;
|
|
1414
|
+
rules[_sx(scope, '.bw_search_input')] = {
|
|
1415
|
+
'background-color': palette.surface || '#fff',
|
|
1416
|
+
'color': palette.dark.base
|
|
1417
|
+
};
|
|
1418
|
+
rules[_sx(scope, '.bw_search_clear')] = {
|
|
1419
|
+
'transition': 'color ' + mo.fast + ' ' + mo.easing + ', background-color ' + mo.fast + ' ' + mo.easing
|
|
1420
|
+
};
|
|
1421
|
+
rules[_sx(scope, '.bw_search_clear:hover')] = { 'color': palette.dark.base };
|
|
1422
|
+
return rules;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
function generateCodeDemoThemed(scope, palette, layout) {
|
|
1319
1426
|
var rules = {};
|
|
1320
|
-
|
|
1427
|
+
var rd = layout ? layout.radius : { card: '0.375rem' };
|
|
1428
|
+
rules[_sx(scope, '.bw_code_demo')] = {
|
|
1429
|
+
'background-color': palette.surface || '#fff',
|
|
1430
|
+
'color': palette.dark.base,
|
|
1431
|
+
'border-radius': rd.card
|
|
1432
|
+
};
|
|
1433
|
+
rules[_sx(scope, '.bw_code_copy_btn_copied')] = {
|
|
1321
1434
|
'background': palette.success.base,
|
|
1322
1435
|
'color': palette.success.textOn,
|
|
1323
1436
|
'border-color': palette.success.base
|
|
1324
1437
|
};
|
|
1325
|
-
rules[
|
|
1438
|
+
rules[_sx(scope, '.bw_copy_btn:hover')] = {
|
|
1326
1439
|
'background': 'rgba(255,255,255,0.2)',
|
|
1327
1440
|
'color': '#fff'
|
|
1328
1441
|
};
|
|
@@ -1332,7 +1445,7 @@
|
|
|
1332
1445
|
function generateNavPillsThemed(scope, palette, layout) {
|
|
1333
1446
|
var rules = {};
|
|
1334
1447
|
var rd = layout.radius;
|
|
1335
|
-
rules[
|
|
1448
|
+
rules[_sx(scope, '.bw_nav_pills .bw_nav_link')] = { 'border-radius': rd.btn };
|
|
1336
1449
|
return rules;
|
|
1337
1450
|
}
|
|
1338
1451
|
|
|
@@ -1358,21 +1471,21 @@
|
|
|
1358
1471
|
var s = palette[k];
|
|
1359
1472
|
|
|
1360
1473
|
// --- Root palette class: sets default bg/color/border ---
|
|
1361
|
-
rules[
|
|
1474
|
+
rules[_sx(scope, '.bw_' + k)] = {
|
|
1362
1475
|
'background-color': s.base,
|
|
1363
1476
|
'color': s.textOn,
|
|
1364
1477
|
'border-color': s.base
|
|
1365
1478
|
};
|
|
1366
1479
|
|
|
1367
1480
|
// --- Pseudo-states (shared across all components) ---
|
|
1368
|
-
rules[
|
|
1481
|
+
rules[_sx(scope, '.bw_' + k + ':hover')] = {
|
|
1369
1482
|
'background-color': s.hover,
|
|
1370
1483
|
'border-color': s.active
|
|
1371
1484
|
};
|
|
1372
|
-
rules[
|
|
1485
|
+
rules[_sx(scope, '.bw_' + k + ':active')] = {
|
|
1373
1486
|
'background-color': s.active
|
|
1374
1487
|
};
|
|
1375
|
-
rules[
|
|
1488
|
+
rules[_sx(scope, '.bw_' + k + ':focus-visible')] = {
|
|
1376
1489
|
'box-shadow': '0 0 0 3px ' + s.focus,
|
|
1377
1490
|
'outline': 'none'
|
|
1378
1491
|
};
|
|
@@ -1380,70 +1493,99 @@
|
|
|
1380
1493
|
// --- Component-specific overrides ---
|
|
1381
1494
|
|
|
1382
1495
|
// Alerts: light bg, dark text, subtle border
|
|
1383
|
-
rules[
|
|
1496
|
+
rules[_sx(scope, '.bw_alert.bw_' + k)] = {
|
|
1384
1497
|
'background-color': s.light,
|
|
1385
1498
|
'color': s.darkText,
|
|
1386
1499
|
'border-color': s.border
|
|
1387
1500
|
};
|
|
1388
1501
|
|
|
1389
1502
|
// Toast: inherit bg, left border accent
|
|
1390
|
-
rules[
|
|
1503
|
+
rules[_sx(scope, '.bw_toast.bw_' + k)] = {
|
|
1391
1504
|
'background-color': 'inherit',
|
|
1392
1505
|
'color': 'inherit',
|
|
1393
1506
|
'border-left': '4px solid ' + s.base
|
|
1394
1507
|
};
|
|
1395
1508
|
|
|
1396
1509
|
// Stat card: inherit bg, left border accent
|
|
1397
|
-
rules[
|
|
1510
|
+
rules[_sx(scope, '.bw_stat_card.bw_' + k)] = {
|
|
1398
1511
|
'background-color': 'inherit',
|
|
1399
1512
|
'color': 'inherit',
|
|
1400
1513
|
'border-left-color': s.base
|
|
1401
1514
|
};
|
|
1402
1515
|
|
|
1403
1516
|
// Card accent: left border accent, inherit bg
|
|
1404
|
-
rules[
|
|
1517
|
+
rules[_sx(scope, '.bw_card.bw_' + k)] = {
|
|
1405
1518
|
'background-color': 'inherit',
|
|
1406
1519
|
'color': 'inherit',
|
|
1407
1520
|
'border-left': '4px solid ' + s.base
|
|
1408
1521
|
};
|
|
1409
1522
|
|
|
1410
1523
|
// Timeline marker: colored dot
|
|
1411
|
-
rules[
|
|
1524
|
+
rules[_sx(scope, '.bw_timeline_marker.bw_' + k)] = {
|
|
1412
1525
|
'box-shadow': '0 0 0 2px ' + s.base
|
|
1413
1526
|
};
|
|
1414
1527
|
|
|
1415
|
-
// Spinner:
|
|
1416
|
-
|
|
1528
|
+
// Spinner: set color, re-apply border pattern so the root palette class
|
|
1529
|
+
// border-color doesn't fill in the transparent gap that makes it spin.
|
|
1530
|
+
// Also neutralize hover/active which would override border-right-color.
|
|
1531
|
+
rules[_sx(scope, '.bw_spinner_border.bw_' + k)] = {
|
|
1417
1532
|
'background-color': 'transparent',
|
|
1418
1533
|
'color': s.base,
|
|
1419
|
-
'border-color':
|
|
1534
|
+
'border-color': s.base,
|
|
1535
|
+
'border-right-color': 'transparent'
|
|
1536
|
+
};
|
|
1537
|
+
rules[_sx(scope, '.bw_spinner_border.bw_' + k + ':hover')] = {
|
|
1538
|
+
'background-color': 'transparent',
|
|
1539
|
+
'border-color': s.base,
|
|
1540
|
+
'border-right-color': 'transparent'
|
|
1541
|
+
};
|
|
1542
|
+
rules[_sx(scope, '.bw_spinner_grow.bw_' + k)] = {
|
|
1543
|
+
'background-color': s.base,
|
|
1544
|
+
'color': s.base
|
|
1420
1545
|
};
|
|
1421
1546
|
|
|
1422
1547
|
// Outline button: transparent bg, colored border+text, solid on hover
|
|
1423
|
-
rules[
|
|
1548
|
+
rules[_sx(scope, '.bw_btn_outline.bw_' + k)] = {
|
|
1424
1549
|
'background-color': 'transparent',
|
|
1425
1550
|
'color': s.base,
|
|
1426
1551
|
'border-color': s.base
|
|
1427
1552
|
};
|
|
1428
|
-
rules[
|
|
1553
|
+
rules[_sx(scope, '.bw_btn_outline.bw_' + k + ':hover')] = {
|
|
1429
1554
|
'background-color': s.base,
|
|
1430
1555
|
'color': s.textOn
|
|
1431
1556
|
};
|
|
1432
1557
|
|
|
1433
1558
|
// Hero: gradient background
|
|
1434
|
-
rules[
|
|
1559
|
+
rules[_sx(scope, '.bw_hero.bw_' + k)] = {
|
|
1435
1560
|
'background': 'linear-gradient(135deg, ' + s.base + ' 0%, ' + s.hover + ' 100%)',
|
|
1436
1561
|
'color': s.textOn
|
|
1437
1562
|
};
|
|
1438
1563
|
|
|
1439
|
-
// Progress bar:
|
|
1440
|
-
rules[
|
|
1441
|
-
'color':
|
|
1564
|
+
// Progress bar: contrasting text on colored bg
|
|
1565
|
+
rules[_sx(scope, '.bw_progress_bar.bw_' + k)] = {
|
|
1566
|
+
'color': s.textOn
|
|
1567
|
+
};
|
|
1568
|
+
|
|
1569
|
+
// Background utility: .bw_bg_primary, .bw_bg_secondary, etc.
|
|
1570
|
+
rules[_sx(scope, '.bw_bg_' + k)] = {
|
|
1571
|
+
'background-color': s.base,
|
|
1572
|
+
'color': s.textOn
|
|
1573
|
+
};
|
|
1574
|
+
|
|
1575
|
+
// Text color utility: .bw_text_primary, .bw_text_secondary, etc.
|
|
1576
|
+
rules[_sx(scope, '.bw_text_' + k)] = {
|
|
1577
|
+
'color': s.base
|
|
1442
1578
|
};
|
|
1443
1579
|
});
|
|
1444
1580
|
|
|
1445
|
-
// Text muted
|
|
1446
|
-
rules[
|
|
1581
|
+
// Text muted — always a neutral gray, never a brand color
|
|
1582
|
+
rules[_sx(scope, '.bw_text_muted')] = { 'color': '#6c757d' };
|
|
1583
|
+
|
|
1584
|
+
// Common bg/text utilities that aren't per-variant
|
|
1585
|
+
rules[_sx(scope, '.bw_bg_dark')] = { 'background-color': '#212529', 'color': '#f8f9fa' };
|
|
1586
|
+
rules[_sx(scope, '.bw_bg_light')] = { 'background-color': '#f8f9fa', 'color': '#212529' };
|
|
1587
|
+
rules[_sx(scope, '.bw_text_light')] = { 'color': '#f8f9fa' };
|
|
1588
|
+
rules[_sx(scope, '.bw_text_dark')] = { 'color': '#212529' };
|
|
1447
1589
|
|
|
1448
1590
|
return rules;
|
|
1449
1591
|
}
|
|
@@ -1465,30 +1607,32 @@
|
|
|
1465
1607
|
generateAlerts(scopeName, palette, layout),
|
|
1466
1608
|
generateCards(scopeName, palette, layout),
|
|
1467
1609
|
generateForms(scopeName, palette, layout),
|
|
1468
|
-
generateNavigation(scopeName, palette),
|
|
1610
|
+
generateNavigation(scopeName, palette, layout),
|
|
1469
1611
|
generateTables(scopeName, palette, layout),
|
|
1470
|
-
generateTabs(scopeName, palette),
|
|
1612
|
+
generateTabs(scopeName, palette, layout),
|
|
1471
1613
|
generateListGroups(scopeName, palette, layout),
|
|
1472
|
-
generatePagination(scopeName, palette),
|
|
1614
|
+
generatePagination(scopeName, palette, layout),
|
|
1473
1615
|
generateProgress(scopeName, palette),
|
|
1474
|
-
generateBreadcrumbThemed(scopeName, palette),
|
|
1616
|
+
generateBreadcrumbThemed(scopeName, palette, layout),
|
|
1475
1617
|
generateCloseButtonThemed(scopeName, palette),
|
|
1476
1618
|
generateSectionsThemed(scopeName, palette),
|
|
1477
|
-
generateAccordionThemed(scopeName, palette),
|
|
1619
|
+
generateAccordionThemed(scopeName, palette, layout),
|
|
1478
1620
|
generateCarouselThemed(scopeName, palette),
|
|
1479
1621
|
generateModalThemed(scopeName, palette, layout),
|
|
1480
1622
|
generateToastThemed(scopeName, palette, layout),
|
|
1481
1623
|
generateDropdownThemed(scopeName, palette, layout),
|
|
1482
1624
|
generateSwitchThemed(scopeName, palette),
|
|
1483
1625
|
generateSkeletonThemed(scopeName, palette),
|
|
1484
|
-
generateStatCardThemed(scopeName, palette),
|
|
1626
|
+
generateStatCardThemed(scopeName, palette, layout),
|
|
1485
1627
|
generateTimelineThemed(scopeName, palette),
|
|
1486
1628
|
generateStepperThemed(scopeName, palette),
|
|
1487
1629
|
generateChipInputThemed(scopeName, palette),
|
|
1488
|
-
generateFileUploadThemed(scopeName, palette),
|
|
1630
|
+
generateFileUploadThemed(scopeName, palette, layout),
|
|
1489
1631
|
generateRangeThemed(scopeName, palette),
|
|
1490
|
-
generateSearchThemed(scopeName, palette),
|
|
1491
|
-
|
|
1632
|
+
generateSearchThemed(scopeName, palette, layout),
|
|
1633
|
+
generateTooltipThemed(scopeName, palette, layout),
|
|
1634
|
+
generatePopoverThemed(scopeName, palette, layout),
|
|
1635
|
+
generateCodeDemoThemed(scopeName, palette, layout),
|
|
1492
1636
|
generateNavPillsThemed(scopeName, palette, layout),
|
|
1493
1637
|
generatePaletteClasses(scopeName, palette)
|
|
1494
1638
|
);
|
|
@@ -1713,6 +1857,8 @@
|
|
|
1713
1857
|
},
|
|
1714
1858
|
'.bw_table caption': { 'font-size': '0.875rem', 'caption-side': 'bottom' },
|
|
1715
1859
|
'.bw_table_bordered > :not(caption) > * > *': { 'border-width': '1px', 'border-style': 'solid' },
|
|
1860
|
+
'.bw_table_selectable > tbody > tr': { 'cursor': 'pointer' },
|
|
1861
|
+
'.bw_table > tbody > tr.bw_table_row_selected > *': { 'background-color': 'rgba(0, 102, 102, 0.1)' },
|
|
1716
1862
|
'.bw_table_responsive': { 'overflow-x': 'auto', '-webkit-overflow-scrolling': 'touch' }
|
|
1717
1863
|
},
|
|
1718
1864
|
|
|
@@ -1766,6 +1912,7 @@
|
|
|
1766
1912
|
'.bw_nav_tabs .bw_nav_item': { 'margin-bottom': '-2px' },
|
|
1767
1913
|
'.bw_nav_link': {
|
|
1768
1914
|
'display': 'block', 'font-size': '0.875rem', 'font-weight': '500',
|
|
1915
|
+
'padding': '0.625rem 1rem',
|
|
1769
1916
|
'text-decoration': 'none', 'cursor': 'pointer',
|
|
1770
1917
|
'border': 'none', 'background': 'transparent', 'font-family': 'inherit'
|
|
1771
1918
|
},
|
|
@@ -1800,10 +1947,11 @@
|
|
|
1800
1947
|
'.bw_page_item': { 'display': 'list-item', 'list-style': 'none' },
|
|
1801
1948
|
'.bw_page_link': {
|
|
1802
1949
|
'position': 'relative', 'display': 'block', 'padding': '0.375rem 0.75rem',
|
|
1803
|
-
'margin-left': '-1px', 'line-height': '1.25', 'text-decoration': 'none'
|
|
1950
|
+
'margin-left': '-1px', 'line-height': '1.25', 'text-decoration': 'none',
|
|
1951
|
+
'border': '1px solid transparent', 'cursor': 'pointer',
|
|
1952
|
+
'font-family': 'inherit', 'font-size': 'inherit', 'background': 'none'
|
|
1804
1953
|
},
|
|
1805
|
-
'.bw_page_item:first-child .bw_page_link': { 'margin-left': '0'
|
|
1806
|
-
'.bw_page_item:last-child .bw_page_link': { 'border-top-right-radius': '0.375rem', 'border-bottom-right-radius': '0.375rem' },
|
|
1954
|
+
'.bw_page_item:first-child .bw_page_link': { 'margin-left': '0' },
|
|
1807
1955
|
'.bw_page_link:focus-visible': { 'z-index': '3', 'outline': '2px solid currentColor', 'outline-offset': '-2px' }
|
|
1808
1956
|
},
|
|
1809
1957
|
|
|
@@ -1960,6 +2108,7 @@
|
|
|
1960
2108
|
'.bw_accordion_header': { 'margin': '0' },
|
|
1961
2109
|
'.bw_accordion_button': {
|
|
1962
2110
|
'position': 'relative', 'display': 'flex', 'align-items': 'center', 'width': '100%',
|
|
2111
|
+
'padding': '0.875rem 1.25rem',
|
|
1963
2112
|
'font-size': '1rem', 'font-weight': '500', 'text-align': 'left',
|
|
1964
2113
|
'background-color': 'transparent', 'border': '0', 'overflow-anchor': 'none', 'cursor': 'pointer',
|
|
1965
2114
|
'font-family': 'inherit'
|
|
@@ -1971,10 +2120,9 @@
|
|
|
1971
2120
|
'background-repeat': 'no-repeat', 'background-size': '1.25rem'
|
|
1972
2121
|
},
|
|
1973
2122
|
'.bw_accordion_button:not(.bw_collapsed)::after': { 'transform': 'rotate(-180deg)' },
|
|
1974
|
-
'.
|
|
1975
|
-
'.bw_accordion_collapse
|
|
1976
|
-
'.
|
|
1977
|
-
'.bw_accordion_item:last-child': { 'border-bottom-left-radius': '8px', 'border-bottom-right-radius': '8px' }
|
|
2123
|
+
'.bw_accordion_body': { 'padding': '1rem 1.25rem' },
|
|
2124
|
+
'.bw_accordion_collapse': { 'max-height': '0', 'overflow': 'hidden', 'transition': 'max-height 0.3s ease' },
|
|
2125
|
+
'.bw_accordion_collapse.bw_collapse_show': { 'max-height': 'none' }
|
|
1978
2126
|
},
|
|
1979
2127
|
|
|
1980
2128
|
// ---- Carousel ----
|
|
@@ -2120,7 +2268,13 @@
|
|
|
2120
2268
|
|
|
2121
2269
|
// ---- Stat card ----
|
|
2122
2270
|
statCard: {
|
|
2123
|
-
'.bw_stat_card': {
|
|
2271
|
+
'.bw_stat_card': {
|
|
2272
|
+
'padding': '1.25rem',
|
|
2273
|
+
'border-left': '4px solid transparent',
|
|
2274
|
+
'border-radius': '0.375rem',
|
|
2275
|
+
'background-color': 'inherit',
|
|
2276
|
+
'transition': 'transform 0.15s ease'
|
|
2277
|
+
},
|
|
2124
2278
|
'.bw_stat_card:hover': { 'transform': 'translateY(-1px)' },
|
|
2125
2279
|
'.bw_stat_icon': { 'font-size': '1.5rem', 'margin-bottom': '0.5rem' },
|
|
2126
2280
|
'.bw_stat_value': { 'font-size': '2rem', 'font-weight': '700', 'line-height': '1.2' },
|
|
@@ -2483,6 +2637,20 @@
|
|
|
2483
2637
|
rules['.list-inline-item'] = { 'display': 'inline-block' };
|
|
2484
2638
|
rules['.list-inline-item:not(:last-child)'] = { 'margin-right': '.5rem' };
|
|
2485
2639
|
|
|
2640
|
+
// Typography — bw_ prefixed utilities via loops
|
|
2641
|
+
var _imp = function(p, v) { var o = {}; o[p] = v + ' !important'; return o; };
|
|
2642
|
+
[['fs',{'xs':'0.75rem','sm':'0.875rem','base':'1rem','lg':'1.125rem','xl':'1.25rem','2xl':'1.5rem'},'font-size'],
|
|
2643
|
+
['fw',{light:'300',normal:'400',medium:'500',semibold:'600',bold:'700'},'font-weight'],
|
|
2644
|
+
['lh',{tight:'1.25',normal:'1.5',relaxed:'1.75'},'line-height']
|
|
2645
|
+
].forEach(function(d) { for (var dk in d[1]) rules['.bw_'+d[0]+'_'+dk] = _imp(d[2], d[1][dk]); });
|
|
2646
|
+
|
|
2647
|
+
// Flex utilities
|
|
2648
|
+
rules['.bw_flex'] = { 'display': 'flex' };
|
|
2649
|
+
rules['.bw_flex_column'] = { 'flex-direction': 'column' };
|
|
2650
|
+
rules['.bw_flex_wrap'] = { 'flex-wrap': 'wrap' };
|
|
2651
|
+
rules['.bw_flex_center'] = { 'display': 'flex', 'align-items': 'center', 'justify-content': 'center' };
|
|
2652
|
+
for (var gk in spacingValues) rules['.bw_gap_' + gk] = { 'gap': spacingValues[gk] + ' !important' };
|
|
2653
|
+
|
|
2486
2654
|
// Visibility
|
|
2487
2655
|
rules['.bw_visible, .visible'] = { 'visibility': 'visible !important' };
|
|
2488
2656
|
rules['.bw_invisible, .invisible'] = { 'visibility': 'hidden !important' };
|
|
@@ -2543,6 +2711,26 @@
|
|
|
2543
2711
|
return getStructuralCSS();
|
|
2544
2712
|
}
|
|
2545
2713
|
|
|
2714
|
+
/**
|
|
2715
|
+
* Get CSS reset rules only (box-sizing, html/body font, reduced-motion).
|
|
2716
|
+
* Separate from themed/structural rules for independent injection.
|
|
2717
|
+
* @returns {Object} CSS rules object for the reset layer
|
|
2718
|
+
*/
|
|
2719
|
+
function getResetStyles() {
|
|
2720
|
+
var rules = {};
|
|
2721
|
+
Object.assign(rules, structuralRules.base);
|
|
2722
|
+
// Include reduced-motion preference
|
|
2723
|
+
rules['@media (prefers-reduced-motion: reduce)'] = {
|
|
2724
|
+
'*, *::before, *::after': {
|
|
2725
|
+
'animation-duration': '0.01ms !important',
|
|
2726
|
+
'animation-iteration-count': '1 !important',
|
|
2727
|
+
'transition-duration': '0.01ms !important',
|
|
2728
|
+
'scroll-behavior': 'auto !important'
|
|
2729
|
+
}
|
|
2730
|
+
};
|
|
2731
|
+
return rules;
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2546
2734
|
// =========================================================================
|
|
2547
2735
|
// defaultStyles — backward-compatible categorized view
|
|
2548
2736
|
// =========================================================================
|
|
@@ -2572,60 +2760,41 @@
|
|
|
2572
2760
|
});
|
|
2573
2761
|
|
|
2574
2762
|
/**
|
|
2575
|
-
*
|
|
2576
|
-
*
|
|
2577
|
-
*
|
|
2578
|
-
*
|
|
2579
|
-
* @param {
|
|
2580
|
-
*
|
|
2581
|
-
* @
|
|
2582
|
-
* @returns {Object} CSS rules object scoped under .bw_theme_alt (+ optional .name)
|
|
2763
|
+
* Prefix every selector in a rules object with a scope selector.
|
|
2764
|
+
* Handles @media/@keyframes blocks and comma-separated selectors.
|
|
2765
|
+
* @param {Object} rules - CSS rules object
|
|
2766
|
+
* @param {string} prefix - Scope prefix (e.g. '#my-dashboard', '.bw_theme_alt')
|
|
2767
|
+
* @param {boolean} [compound=false] - If true, use compound selector (no space)
|
|
2768
|
+
* for the first segment: `#scope.bw_theme_alt .sel` vs `#scope .sel`
|
|
2769
|
+
* @returns {Object} New rules object with scoped selectors
|
|
2583
2770
|
*/
|
|
2584
|
-
function
|
|
2585
|
-
|
|
2586
|
-
var
|
|
2587
|
-
|
|
2588
|
-
// Re-scope every selector under .bw_theme_alt (+ optional theme name)
|
|
2589
|
-
var altPrefix = name ? '.' + name + '.bw_theme_alt' : '.bw_theme_alt';
|
|
2590
|
-
var altRules = {};
|
|
2591
|
-
|
|
2592
|
-
for (var sel in rawRules) {
|
|
2593
|
-
if (!rawRules.hasOwnProperty(sel)) continue;
|
|
2594
|
-
|
|
2771
|
+
function scopeRulesUnder(rules, prefix, compound) {
|
|
2772
|
+
var scoped = {};
|
|
2773
|
+
for (var sel in rules) {
|
|
2774
|
+
if (!rules.hasOwnProperty(sel)) continue;
|
|
2595
2775
|
if (sel.charAt(0) === '@') {
|
|
2596
2776
|
// @media / @keyframes — recurse into the block
|
|
2597
|
-
var innerBlock =
|
|
2598
|
-
var
|
|
2777
|
+
var innerBlock = rules[sel];
|
|
2778
|
+
var scopedInner = {};
|
|
2599
2779
|
for (var innerSel in innerBlock) {
|
|
2600
2780
|
if (!innerBlock.hasOwnProperty(innerSel)) continue;
|
|
2601
|
-
|
|
2781
|
+
scopedInner[_prefixSelector(innerSel, prefix)] = innerBlock[innerSel];
|
|
2602
2782
|
}
|
|
2603
|
-
|
|
2783
|
+
scoped[sel] = scopedInner;
|
|
2604
2784
|
} else {
|
|
2605
|
-
|
|
2606
|
-
// Handle comma-separated selectors
|
|
2607
|
-
var parts = sel.split(',');
|
|
2608
|
-
var scopedParts = [];
|
|
2609
|
-
for (var i = 0; i < parts.length; i++) {
|
|
2610
|
-
var s = parts[i].trim();
|
|
2611
|
-
// 'body' selector gets special treatment: .bw_theme_alt body
|
|
2612
|
-
if (s === 'body' || s.indexOf('body') === 0) {
|
|
2613
|
-
scopedParts.push(altPrefix + ' ' + s);
|
|
2614
|
-
} else {
|
|
2615
|
-
scopedParts.push(altPrefix + ' ' + s);
|
|
2616
|
-
}
|
|
2617
|
-
}
|
|
2618
|
-
altRules[scopedParts.join(', ')] = rawRules[sel];
|
|
2785
|
+
scoped[_prefixSelector(sel, prefix)] = rules[sel];
|
|
2619
2786
|
}
|
|
2620
2787
|
}
|
|
2788
|
+
return scoped;
|
|
2789
|
+
}
|
|
2621
2790
|
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
return
|
|
2791
|
+
function _prefixSelector(sel, prefix) {
|
|
2792
|
+
var parts = sel.split(',');
|
|
2793
|
+
var result = [];
|
|
2794
|
+
for (var i = 0; i < parts.length; i++) {
|
|
2795
|
+
result.push(prefix + ' ' + parts[i].trim());
|
|
2796
|
+
}
|
|
2797
|
+
return result.join(', ');
|
|
2629
2798
|
}
|
|
2630
2799
|
|
|
2631
2800
|
/**
|
|
@@ -3597,7 +3766,7 @@
|
|
|
3597
3766
|
if (breakpoint === 'xs') {
|
|
3598
3767
|
classes.push(`bw_col_${value}`);
|
|
3599
3768
|
} else {
|
|
3600
|
-
classes.push(`bw_col_${breakpoint}
|
|
3769
|
+
classes.push(`bw_col_${breakpoint}_${value}`);
|
|
3601
3770
|
}
|
|
3602
3771
|
});
|
|
3603
3772
|
} else if (size) {
|
|
@@ -4980,8 +5149,8 @@
|
|
|
4980
5149
|
t: 'li',
|
|
4981
5150
|
a: { class: `bw_page_item ${currentPage <= 1 ? 'bw_disabled' : ''}`.trim() },
|
|
4982
5151
|
c: {
|
|
4983
|
-
t: '
|
|
4984
|
-
a: { class: 'bw_page_link',
|
|
5152
|
+
t: 'button',
|
|
5153
|
+
a: { class: 'bw_page_link', type: 'button', onclick: handleClick(currentPage - 1), 'aria-label': 'Previous', disabled: currentPage <= 1 ? true : undefined },
|
|
4985
5154
|
c: '\u2039'
|
|
4986
5155
|
}
|
|
4987
5156
|
});
|
|
@@ -4993,8 +5162,8 @@
|
|
|
4993
5162
|
t: 'li',
|
|
4994
5163
|
a: { class: `bw_page_item ${pageNum === currentPage ? 'bw_active' : ''}`.trim() },
|
|
4995
5164
|
c: {
|
|
4996
|
-
t: '
|
|
4997
|
-
a: { class: 'bw_page_link',
|
|
5165
|
+
t: 'button',
|
|
5166
|
+
a: { class: 'bw_page_link', type: 'button', onclick: handleClick(pageNum), 'aria-current': pageNum === currentPage ? 'page' : undefined },
|
|
4998
5167
|
c: '' + pageNum
|
|
4999
5168
|
}
|
|
5000
5169
|
});
|
|
@@ -5006,8 +5175,8 @@
|
|
|
5006
5175
|
t: 'li',
|
|
5007
5176
|
a: { class: `bw_page_item ${currentPage >= pages ? 'bw_disabled' : ''}`.trim() },
|
|
5008
5177
|
c: {
|
|
5009
|
-
t: '
|
|
5010
|
-
a: { class: 'bw_page_link',
|
|
5178
|
+
t: 'button',
|
|
5179
|
+
a: { class: 'bw_page_link', type: 'button', onclick: handleClick(currentPage + 1), 'aria-label': 'Next', disabled: currentPage >= pages ? true : undefined },
|
|
5011
5180
|
c: '\u203A'
|
|
5012
5181
|
}
|
|
5013
5182
|
});
|
|
@@ -6880,7 +7049,11 @@
|
|
|
6880
7049
|
function make(type, props) {
|
|
6881
7050
|
var def = BCCL[type];
|
|
6882
7051
|
if (!def) throw new Error('bw.make: unknown component type "' + type + '". Available: ' + Object.keys(BCCL).join(', '));
|
|
6883
|
-
|
|
7052
|
+
var taco = def.make(props || {});
|
|
7053
|
+
if (taco && typeof taco === 'object') {
|
|
7054
|
+
taco._bwFactory = { type: type, props: props || {} };
|
|
7055
|
+
}
|
|
7056
|
+
return taco;
|
|
6884
7057
|
}
|
|
6885
7058
|
|
|
6886
7059
|
var components = /*#__PURE__*/Object.freeze({
|
|
@@ -7001,7 +7174,7 @@
|
|
|
7001
7174
|
__monkey_patch_is_nodejs__: {
|
|
7002
7175
|
_value: 'ignore',
|
|
7003
7176
|
set: function(x) {
|
|
7004
|
-
this._value = (
|
|
7177
|
+
this._value = _is(x, 'boolean') ? x : 'ignore';
|
|
7005
7178
|
},
|
|
7006
7179
|
get: function() {
|
|
7007
7180
|
return this._value;
|
|
@@ -7049,6 +7222,67 @@
|
|
|
7049
7222
|
configurable: true
|
|
7050
7223
|
});
|
|
7051
7224
|
|
|
7225
|
+
// ── Internal aliases ─────────────────────────────────────────────────────
|
|
7226
|
+
// Short names for frequently-used builtins and internal methods.
|
|
7227
|
+
// Same pattern as v1 (_to = bw.typeOf, etc.).
|
|
7228
|
+
//
|
|
7229
|
+
// Why: Terser can't shorten global property chains (console.warn,
|
|
7230
|
+
// Object.prototype.hasOwnProperty, Array.isArray, document.createElement)
|
|
7231
|
+
// because it can't prove they're side-effect-free. We can, so we alias
|
|
7232
|
+
// them here. Each alias saves bytes in the minified output, and the short
|
|
7233
|
+
// names also reduce visual noise in the hot paths (binding pipeline,
|
|
7234
|
+
// createDOM, etc.).
|
|
7235
|
+
//
|
|
7236
|
+
// Alias Target Sites
|
|
7237
|
+
// ───────── ────────────────────────────────────── ─────
|
|
7238
|
+
// _hop Object.prototype.hasOwnProperty 15
|
|
7239
|
+
// _isA Array.isArray 25
|
|
7240
|
+
// _keys Object.keys 7
|
|
7241
|
+
// _to bw.typeOf (type string) 26
|
|
7242
|
+
// _is type check boolean: _is(x,'string') ~50
|
|
7243
|
+
// _cw console.warn 8
|
|
7244
|
+
// _cl console.log 11
|
|
7245
|
+
// _ce console.error 4
|
|
7246
|
+
// _chp ComponentHandle.prototype 28 (defined after constructor)
|
|
7247
|
+
//
|
|
7248
|
+
// Note: document.createElement etc. are NOT aliased because they require
|
|
7249
|
+
// `this === document` and .bind() would add overhead on every call.
|
|
7250
|
+
// Console aliases use thin wrappers (not direct refs) so test monkey-
|
|
7251
|
+
// patching of console.warn/log/error continues to work.
|
|
7252
|
+
//
|
|
7253
|
+
// `typeof x` for UNDECLARED globals (window, document, process, require,
|
|
7254
|
+
// EventSource, navigator, Promise, __filename, import.meta) MUST stay as
|
|
7255
|
+
// raw `typeof` — calling _to(x) when x doesn't exist throws ReferenceError.
|
|
7256
|
+
//
|
|
7257
|
+
// ── v1 functional type helpers (kept for reference, not currently used) ──
|
|
7258
|
+
// _toa(x, type, trueVal, falseVal) — bw.typeAssign:
|
|
7259
|
+
// returns trueVal if _to(x)===type, else falseVal.
|
|
7260
|
+
// Replaces: (typeof x === 'string') ? A : B → _toa(x,'string',A,B)
|
|
7261
|
+
// _toc(x, type, trueVal, falseVal) — bw.typeConvert:
|
|
7262
|
+
// same as _toa but if trueVal/falseVal are functions, calls them with x.
|
|
7263
|
+
// Replaces: typeof x === 'string' ? fn(x) : default → _toc(x,'string',fn,default)
|
|
7264
|
+
// Uncomment if pattern frequency justifies them:
|
|
7265
|
+
// var _toa = function(x, t, y, n) { return _to(x) === t ? y : n; };
|
|
7266
|
+
// 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); };
|
|
7267
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
7268
|
+
var _hop = Object.prototype.hasOwnProperty;
|
|
7269
|
+
var _isA = Array.isArray;
|
|
7270
|
+
var _keys = Object.keys;
|
|
7271
|
+
var _to = typeOf; // imported from bitwrench-utils.js
|
|
7272
|
+
var _is = function(x, t) { var r = _to(x); return r === t || r.toLowerCase() === t; };
|
|
7273
|
+
// Console aliases use thin wrappers (not direct references) so that test
|
|
7274
|
+
// code can monkey-patch console.warn/log/error and the patches take effect.
|
|
7275
|
+
var _cw = function() { console.warn.apply(console, arguments); };
|
|
7276
|
+
var _cl = function() { console.log.apply(console, arguments); };
|
|
7277
|
+
var _ce = function() { console.error.apply(console, arguments); };
|
|
7278
|
+
|
|
7279
|
+
/**
|
|
7280
|
+
* Debug flag. When true, emits console.warn for silent binding failures
|
|
7281
|
+
* (missing paths, null refs, auto-created intermediate objects).
|
|
7282
|
+
* @type {boolean}
|
|
7283
|
+
*/
|
|
7284
|
+
bw.debug = false;
|
|
7285
|
+
|
|
7052
7286
|
/**
|
|
7053
7287
|
* Lazy-resolve Node.js `fs` module.
|
|
7054
7288
|
* Tries require('fs') first (available in CJS/UMD Node.js builds),
|
|
@@ -7196,7 +7430,7 @@
|
|
|
7196
7430
|
*/
|
|
7197
7431
|
bw._el = function(id) {
|
|
7198
7432
|
// Pass-through for DOM elements
|
|
7199
|
-
if (
|
|
7433
|
+
if (!_is(id, 'string')) return id || null;
|
|
7200
7434
|
if (!id) return null;
|
|
7201
7435
|
if (!bw._isBrowser) return null;
|
|
7202
7436
|
|
|
@@ -7224,7 +7458,12 @@
|
|
|
7224
7458
|
el = document.querySelector('[data-bw_id="' + id + '"]');
|
|
7225
7459
|
}
|
|
7226
7460
|
|
|
7227
|
-
// 5.
|
|
7461
|
+
// 5. Try class-based lookup for bw_uuid_* tokens (UUID addressing)
|
|
7462
|
+
if (!el && id.indexOf('bw_uuid_') === 0) {
|
|
7463
|
+
el = document.querySelector('.' + id);
|
|
7464
|
+
}
|
|
7465
|
+
|
|
7466
|
+
// 6. Cache the result for next time
|
|
7228
7467
|
if (el) {
|
|
7229
7468
|
bw._nodeMap[id] = el;
|
|
7230
7469
|
}
|
|
@@ -7277,6 +7516,84 @@
|
|
|
7277
7516
|
}
|
|
7278
7517
|
};
|
|
7279
7518
|
|
|
7519
|
+
// ===================================================================================
|
|
7520
|
+
// bw.assignUUID() / bw.getUUID() — Explicit UUID addressing for TACO objects
|
|
7521
|
+
// ===================================================================================
|
|
7522
|
+
|
|
7523
|
+
/**
|
|
7524
|
+
* Regex to match a bw_uuid_* token in a class string.
|
|
7525
|
+
* @private
|
|
7526
|
+
*/
|
|
7527
|
+
var _UUID_RE = /\bbw_uuid_[a-z0-9_]+\b/;
|
|
7528
|
+
|
|
7529
|
+
/**
|
|
7530
|
+
* Assign a UUID to a TACO object by appending a `bw_uuid_*` token to `taco.a.class`.
|
|
7531
|
+
*
|
|
7532
|
+
* Idempotent by default — calling twice returns the same UUID. Pass `forceNew=true`
|
|
7533
|
+
* to replace an existing UUID (useful in loops where each TACO needs a unique ID).
|
|
7534
|
+
*
|
|
7535
|
+
* @param {Object} taco - A TACO object `{t, a, c, o}`
|
|
7536
|
+
* @param {boolean} [forceNew=false] - If true, replaces any existing UUID with a new one
|
|
7537
|
+
* @returns {string} The UUID string (e.g. 'bw_uuid_a1b2c3d4e5')
|
|
7538
|
+
* @category Identifiers
|
|
7539
|
+
* @example
|
|
7540
|
+
* var card = bw.makeStatCard({ value: '0', label: 'Scans' });
|
|
7541
|
+
* var uuid = bw.assignUUID(card); // 'bw_uuid_a1b2c3d4e5'
|
|
7542
|
+
* var same = bw.assignUUID(card); // same UUID (idempotent)
|
|
7543
|
+
* var diff = bw.assignUUID(card, true); // new UUID (forced)
|
|
7544
|
+
*/
|
|
7545
|
+
bw.assignUUID = function(taco, forceNew) {
|
|
7546
|
+
if (!taco || !_is(taco, 'object')) return null;
|
|
7547
|
+
|
|
7548
|
+
// Ensure taco.a exists
|
|
7549
|
+
if (!taco.a) taco.a = {};
|
|
7550
|
+
if (!_is(taco.a.class, 'string')) taco.a.class = taco.a.class ? String(taco.a.class) : '';
|
|
7551
|
+
|
|
7552
|
+
var existing = taco.a.class.match(_UUID_RE);
|
|
7553
|
+
|
|
7554
|
+
if (existing && !forceNew) {
|
|
7555
|
+
return existing[0];
|
|
7556
|
+
}
|
|
7557
|
+
|
|
7558
|
+
// Remove old UUID if forceNew
|
|
7559
|
+
if (existing) {
|
|
7560
|
+
taco.a.class = taco.a.class.replace(_UUID_RE, '').replace(/\s+/g, ' ').trim();
|
|
7561
|
+
}
|
|
7562
|
+
|
|
7563
|
+
var uuid = bw.uuid('uuid');
|
|
7564
|
+
taco.a.class = (taco.a.class ? taco.a.class + ' ' : '') + uuid;
|
|
7565
|
+
return uuid;
|
|
7566
|
+
};
|
|
7567
|
+
|
|
7568
|
+
/**
|
|
7569
|
+
* Read the UUID from a TACO object or DOM element. Pure getter, no side effects.
|
|
7570
|
+
*
|
|
7571
|
+
* @param {Object|Element} tacoOrElement - A TACO object or DOM element
|
|
7572
|
+
* @returns {string|null} The UUID string, or null if none assigned
|
|
7573
|
+
* @category Identifiers
|
|
7574
|
+
* @example
|
|
7575
|
+
* bw.getUUID(card) // 'bw_uuid_a1b2c3d4e5' (from TACO)
|
|
7576
|
+
* bw.getUUID(domEl) // 'bw_uuid_a1b2c3d4e5' (from DOM element)
|
|
7577
|
+
* bw.getUUID({t:'div'}) // null (no UUID)
|
|
7578
|
+
*/
|
|
7579
|
+
bw.getUUID = function(tacoOrElement) {
|
|
7580
|
+
if (!tacoOrElement) return null;
|
|
7581
|
+
|
|
7582
|
+
var classStr;
|
|
7583
|
+
// DOM element: check className
|
|
7584
|
+
if (tacoOrElement.className !== undefined && tacoOrElement.tagName) {
|
|
7585
|
+
classStr = tacoOrElement.className;
|
|
7586
|
+
}
|
|
7587
|
+
// TACO object: check a.class
|
|
7588
|
+
else if (tacoOrElement.a && _is(tacoOrElement.a.class, 'string')) {
|
|
7589
|
+
classStr = tacoOrElement.a.class;
|
|
7590
|
+
}
|
|
7591
|
+
|
|
7592
|
+
if (!classStr) return null;
|
|
7593
|
+
var match = classStr.match(_UUID_RE);
|
|
7594
|
+
return match ? match[0] : null;
|
|
7595
|
+
};
|
|
7596
|
+
|
|
7280
7597
|
/**
|
|
7281
7598
|
* Escape HTML special characters to prevent XSS.
|
|
7282
7599
|
*
|
|
@@ -7292,7 +7609,7 @@
|
|
|
7292
7609
|
* // => '<b>Hello</b> & "world"'
|
|
7293
7610
|
*/
|
|
7294
7611
|
bw.escapeHTML = function(str) {
|
|
7295
|
-
if (
|
|
7612
|
+
if (!_is(str, 'string')) return '';
|
|
7296
7613
|
|
|
7297
7614
|
const escapeMap = {
|
|
7298
7615
|
'&': '&',
|
|
@@ -7326,6 +7643,42 @@
|
|
|
7326
7643
|
return { __bw_raw: true, v: String(str) };
|
|
7327
7644
|
};
|
|
7328
7645
|
|
|
7646
|
+
/**
|
|
7647
|
+
* Hyperscript-style TACO constructor.
|
|
7648
|
+
*
|
|
7649
|
+
* A convenience helper that returns a canonical TACO object from positional
|
|
7650
|
+
* arguments. The return value is a plain object — serializable, works with
|
|
7651
|
+
* bwserve, and accepted everywhere TACO is accepted.
|
|
7652
|
+
*
|
|
7653
|
+
* @param {string} tag - HTML tag name (e.g. 'div', 'p', 'section')
|
|
7654
|
+
* @param {Object|null} [attrs] - HTML attributes object. Pass null or omit to skip.
|
|
7655
|
+
* @param {*} [content] - Content: string, number, TACO object, or array of children.
|
|
7656
|
+
* @param {Object} [options] - TACO options (state, lifecycle hooks, render fn).
|
|
7657
|
+
* @returns {Object} Plain TACO object {t, a?, c?, o?}
|
|
7658
|
+
* @category Utilities
|
|
7659
|
+
* @see bw.html
|
|
7660
|
+
* @see bw.createDOM
|
|
7661
|
+
* @see bw.DOM
|
|
7662
|
+
* @example
|
|
7663
|
+
* bw.h('div')
|
|
7664
|
+
* // => { t: 'div' }
|
|
7665
|
+
*
|
|
7666
|
+
* bw.h('p', { class: 'bw_text_muted' }, 'Hello')
|
|
7667
|
+
* // => { t: 'p', a: { class: 'bw_text_muted' }, c: 'Hello' }
|
|
7668
|
+
*
|
|
7669
|
+
* bw.h('ul', null, [
|
|
7670
|
+
* bw.h('li', null, 'one'),
|
|
7671
|
+
* bw.h('li', null, 'two')
|
|
7672
|
+
* ])
|
|
7673
|
+
* // => { t: 'ul', c: [{ t: 'li', c: 'one' }, { t: 'li', c: 'two' }] }
|
|
7674
|
+
*/
|
|
7675
|
+
bw.h = function(tag, attrs, content, options) {
|
|
7676
|
+
var taco = { t: String(tag) };
|
|
7677
|
+
if (attrs !== null && attrs !== undefined) taco.a = attrs;
|
|
7678
|
+
if (content !== undefined) taco.c = content;
|
|
7679
|
+
if (options !== undefined) taco.o = options;
|
|
7680
|
+
return taco;
|
|
7681
|
+
};
|
|
7329
7682
|
|
|
7330
7683
|
/**
|
|
7331
7684
|
* Convert a TACO object (or array of TACOs) to an HTML string.
|
|
@@ -7365,7 +7718,7 @@
|
|
|
7365
7718
|
}
|
|
7366
7719
|
|
|
7367
7720
|
// Handle arrays of TACOs
|
|
7368
|
-
if (
|
|
7721
|
+
if (_isA(taco)) {
|
|
7369
7722
|
return taco.map(t => bw.html(t, options)).join('');
|
|
7370
7723
|
}
|
|
7371
7724
|
|
|
@@ -7388,15 +7741,15 @@
|
|
|
7388
7741
|
if (taco && taco._bwEach && options.state) {
|
|
7389
7742
|
var eachExpr = taco.expr.replace(/^\$\{|\}$/g, '');
|
|
7390
7743
|
var arr = bw._evaluatePath(options.state, eachExpr);
|
|
7391
|
-
if (!
|
|
7744
|
+
if (!_isA(arr)) return '';
|
|
7392
7745
|
return arr.map(function(item, idx) { return bw.html(taco.factory(item, idx), options); }).join('');
|
|
7393
7746
|
}
|
|
7394
7747
|
|
|
7395
7748
|
// Handle primitives and non-TACO objects
|
|
7396
|
-
if (
|
|
7749
|
+
if (!_is(taco, 'object') || !taco.t) {
|
|
7397
7750
|
var str = options.raw ? String(taco) : bw.escapeHTML(String(taco));
|
|
7398
7751
|
// Resolve template bindings if state provided
|
|
7399
|
-
if (options.state &&
|
|
7752
|
+
if (options.state && _is(str, 'string') && str.indexOf('${') >= 0) {
|
|
7400
7753
|
str = bw._resolveTemplate(str, options.state, !!options.compile);
|
|
7401
7754
|
}
|
|
7402
7755
|
return str;
|
|
@@ -7416,10 +7769,18 @@
|
|
|
7416
7769
|
// Skip null, undefined, false
|
|
7417
7770
|
if (value == null || value === false) continue;
|
|
7418
7771
|
|
|
7419
|
-
//
|
|
7420
|
-
if (key.startsWith('on'))
|
|
7772
|
+
// Serialize event handlers via funcRegister
|
|
7773
|
+
if (key.startsWith('on')) {
|
|
7774
|
+
if (_is(value, 'function')) {
|
|
7775
|
+
var fnId = bw.funcRegister(value);
|
|
7776
|
+
attrStr += ' ' + key + '="' + bw.funcGetDispatchStr(fnId, 'event') + '"';
|
|
7777
|
+
} else if (_is(value, 'string')) {
|
|
7778
|
+
attrStr += ' ' + key + '="' + bw.escapeHTML(value) + '"';
|
|
7779
|
+
}
|
|
7780
|
+
continue;
|
|
7781
|
+
}
|
|
7421
7782
|
|
|
7422
|
-
if (key === 'style' &&
|
|
7783
|
+
if (key === 'style' && _is(value, 'object')) {
|
|
7423
7784
|
// Convert style object to string
|
|
7424
7785
|
const styleStr = Object.entries(value)
|
|
7425
7786
|
.filter(([, v]) => v != null)
|
|
@@ -7430,7 +7791,7 @@
|
|
|
7430
7791
|
}
|
|
7431
7792
|
} else if (key === 'class') {
|
|
7432
7793
|
// Handle class as array or string
|
|
7433
|
-
const classStr =
|
|
7794
|
+
const classStr = _isA(value) ? value.filter(Boolean).join(' ') : String(value);
|
|
7434
7795
|
if (classStr) {
|
|
7435
7796
|
attrStr += ` class="${bw.escapeHTML(classStr)}"`;
|
|
7436
7797
|
}
|
|
@@ -7466,13 +7827,184 @@
|
|
|
7466
7827
|
// Process content recursively
|
|
7467
7828
|
let contentStr = content != null ? bw.html(content, options) : '';
|
|
7468
7829
|
// Resolve template bindings in content if state provided
|
|
7469
|
-
if (options.state &&
|
|
7830
|
+
if (options.state && _is(contentStr, 'string') && contentStr.indexOf('${') >= 0) {
|
|
7470
7831
|
contentStr = bw._resolveTemplate(contentStr, options.state, !!options.compile);
|
|
7471
7832
|
}
|
|
7472
7833
|
|
|
7473
7834
|
return `<${tag}${attrStr}>${contentStr}</${tag}>`;
|
|
7474
7835
|
};
|
|
7475
7836
|
|
|
7837
|
+
/**
|
|
7838
|
+
* Generate a complete, self-contained HTML document from TACO content.
|
|
7839
|
+
*
|
|
7840
|
+
* Produces a full `<!DOCTYPE html>` page with configurable runtime injection,
|
|
7841
|
+
* func registry emission (so serialized event handlers work), optional theme,
|
|
7842
|
+
* and extra head elements. Designed for static site generation, offline/airgapped
|
|
7843
|
+
* use, and the "static site that isn't static" workflow.
|
|
7844
|
+
*
|
|
7845
|
+
* @param {Object} [opts={}] - Page options
|
|
7846
|
+
* @param {Object|string|Array} [opts.body=''] - Body content: TACO, string, or array
|
|
7847
|
+
* @param {string} [opts.title='bitwrench'] - Page title
|
|
7848
|
+
* @param {Object} [opts.state] - State for ${expr} resolution in bw.html()
|
|
7849
|
+
* @param {string} [opts.runtime='shim'] - Runtime level: 'inline'|'cdn'|'shim'|'none'
|
|
7850
|
+
* @param {string} [opts.css=''] - Additional CSS for <style> block
|
|
7851
|
+
* @param {string|Object} [opts.theme=null] - Theme preset name or config object
|
|
7852
|
+
* @param {Array} [opts.head=[]] - Extra TACO elements rendered into <head>
|
|
7853
|
+
* @param {string} [opts.favicon=''] - Favicon URL
|
|
7854
|
+
* @param {string} [opts.lang='en'] - HTML lang attribute
|
|
7855
|
+
* @returns {string} Complete HTML document string
|
|
7856
|
+
* @category DOM Generation
|
|
7857
|
+
* @see bw.html
|
|
7858
|
+
* @example
|
|
7859
|
+
* bw.htmlPage({
|
|
7860
|
+
* title: 'My App',
|
|
7861
|
+
* body: { t: 'h1', c: 'Hello World' },
|
|
7862
|
+
* runtime: 'shim'
|
|
7863
|
+
* })
|
|
7864
|
+
*/
|
|
7865
|
+
bw.htmlPage = function(opts) {
|
|
7866
|
+
opts = opts || {};
|
|
7867
|
+
var title = opts.title || 'bitwrench';
|
|
7868
|
+
var body = opts.body || '';
|
|
7869
|
+
var state = opts.state || undefined;
|
|
7870
|
+
var runtime = opts.runtime || 'shim';
|
|
7871
|
+
var css = opts.css || '';
|
|
7872
|
+
var theme = opts.theme || null;
|
|
7873
|
+
var headExtra = opts.head || [];
|
|
7874
|
+
var favicon = opts.favicon || '';
|
|
7875
|
+
var lang = opts.lang || 'en';
|
|
7876
|
+
|
|
7877
|
+
// Snapshot funcRegistry counter before rendering
|
|
7878
|
+
var fnCounterBefore = bw._fnIDCounter;
|
|
7879
|
+
|
|
7880
|
+
// Render body content
|
|
7881
|
+
var bodyHTML = '';
|
|
7882
|
+
if (_is(body, 'string')) {
|
|
7883
|
+
bodyHTML = body;
|
|
7884
|
+
} else {
|
|
7885
|
+
var htmlOpts = {};
|
|
7886
|
+
if (state) htmlOpts.state = state;
|
|
7887
|
+
bodyHTML = bw.html(body, htmlOpts);
|
|
7888
|
+
}
|
|
7889
|
+
|
|
7890
|
+
// Collect functions registered during this render
|
|
7891
|
+
var fnCounterAfter = bw._fnIDCounter;
|
|
7892
|
+
var registryEntries = '';
|
|
7893
|
+
for (var i = fnCounterBefore; i < fnCounterAfter; i++) {
|
|
7894
|
+
var fnKey = 'bw_fn_' + i;
|
|
7895
|
+
if (bw._fnRegistry[fnKey]) {
|
|
7896
|
+
registryEntries += 'bw._fnRegistry[\'' + fnKey + '\']=' +
|
|
7897
|
+
bw._fnRegistry[fnKey].toString() + ';\n';
|
|
7898
|
+
}
|
|
7899
|
+
}
|
|
7900
|
+
|
|
7901
|
+
// Build runtime script for <head>
|
|
7902
|
+
var runtimeHead = '';
|
|
7903
|
+
if (runtime === 'inline') {
|
|
7904
|
+
// Read UMD bundle synchronously if in Node.js
|
|
7905
|
+
var umdSource = null;
|
|
7906
|
+
if (bw._isNode) {
|
|
7907
|
+
try {
|
|
7908
|
+
var fs = (typeof require === 'function') ? require('fs') : null;
|
|
7909
|
+
var pathMod = (typeof require === 'function') ? require('path') : null;
|
|
7910
|
+
if (fs && pathMod) {
|
|
7911
|
+
// Resolve dist/ relative to this source file
|
|
7912
|
+
var srcDir = '';
|
|
7913
|
+
try { srcDir = pathMod.dirname((typeof __filename !== 'undefined') ? __filename : ''); }
|
|
7914
|
+
catch(e2) { /* ESM: __filename not available */ }
|
|
7915
|
+
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.umd.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.umd.js', document.baseURI).href))) {
|
|
7916
|
+
var url = (typeof require === 'function') ? require('url') : null;
|
|
7917
|
+
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.umd.js', document.baseURI).href))));
|
|
7918
|
+
}
|
|
7919
|
+
if (srcDir) {
|
|
7920
|
+
var distPath = pathMod.resolve(srcDir, '../dist/bitwrench.umd.min.js');
|
|
7921
|
+
umdSource = fs.readFileSync(distPath, 'utf8');
|
|
7922
|
+
}
|
|
7923
|
+
}
|
|
7924
|
+
} catch(e) { /* fall through */ }
|
|
7925
|
+
}
|
|
7926
|
+
if (umdSource) {
|
|
7927
|
+
runtimeHead = '<script>' + umdSource + '</script>';
|
|
7928
|
+
} else {
|
|
7929
|
+
// Fallback to shim in browser or if dist not available
|
|
7930
|
+
runtimeHead = '<script>' + bw._FUNC_REGISTRY_SHIM + '</script>';
|
|
7931
|
+
}
|
|
7932
|
+
} else if (runtime === 'cdn') {
|
|
7933
|
+
runtimeHead = '<script src="https://cdn.jsdelivr.net/npm/bitwrench@2/dist/bitwrench.umd.min.js"></script>';
|
|
7934
|
+
} else if (runtime === 'shim') {
|
|
7935
|
+
runtimeHead = '<script>' + bw._FUNC_REGISTRY_SHIM + '</script>';
|
|
7936
|
+
}
|
|
7937
|
+
// runtime === 'none' → empty
|
|
7938
|
+
|
|
7939
|
+
// Theme CSS
|
|
7940
|
+
var themeCSS = '';
|
|
7941
|
+
if (theme) {
|
|
7942
|
+
var themeConfig = _is(theme, 'string')
|
|
7943
|
+
? (THEME_PRESETS[theme.toLowerCase()] || null)
|
|
7944
|
+
: theme;
|
|
7945
|
+
if (themeConfig) {
|
|
7946
|
+
var themeResult = bw.makeStyles(themeConfig);
|
|
7947
|
+
themeCSS = themeResult.css;
|
|
7948
|
+
}
|
|
7949
|
+
}
|
|
7950
|
+
|
|
7951
|
+
// Extra <head> elements
|
|
7952
|
+
var headHTML = '';
|
|
7953
|
+
if (_isA(headExtra) && headExtra.length > 0) {
|
|
7954
|
+
headHTML = headExtra.map(function(el) { return bw.html(el); }).join('\n');
|
|
7955
|
+
}
|
|
7956
|
+
|
|
7957
|
+
// Favicon
|
|
7958
|
+
var faviconTag = '';
|
|
7959
|
+
if (favicon) {
|
|
7960
|
+
var safeFavicon = favicon.replace(/[&<>"']/g, function(c) {
|
|
7961
|
+
return ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c];
|
|
7962
|
+
});
|
|
7963
|
+
faviconTag = '<link rel="icon" href="' + safeFavicon + '">';
|
|
7964
|
+
}
|
|
7965
|
+
|
|
7966
|
+
// Escaped title
|
|
7967
|
+
var safeTitle = bw.escapeHTML(title);
|
|
7968
|
+
|
|
7969
|
+
// Combine all CSS
|
|
7970
|
+
var allCSS = (themeCSS ? themeCSS + '\n' : '') + css;
|
|
7971
|
+
|
|
7972
|
+
// Body-end script: registry entries + optional loadStyles
|
|
7973
|
+
var bodyEndScript = '';
|
|
7974
|
+
var bodyEndParts = [];
|
|
7975
|
+
if (registryEntries) {
|
|
7976
|
+
bodyEndParts.push(registryEntries);
|
|
7977
|
+
}
|
|
7978
|
+
if (runtime === 'inline' || runtime === 'cdn') {
|
|
7979
|
+
bodyEndParts.push('if(typeof bw!=="undefined"){bw.loadStyles();}');
|
|
7980
|
+
}
|
|
7981
|
+
if (bodyEndParts.length > 0) {
|
|
7982
|
+
bodyEndScript = '<script>\n' + bodyEndParts.join('\n') + '\n</script>';
|
|
7983
|
+
}
|
|
7984
|
+
|
|
7985
|
+
// Assemble document
|
|
7986
|
+
var parts = [
|
|
7987
|
+
'<!DOCTYPE html>',
|
|
7988
|
+
'<html lang="' + lang + '">',
|
|
7989
|
+
'<head>',
|
|
7990
|
+
'<meta charset="UTF-8">',
|
|
7991
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1">'
|
|
7992
|
+
];
|
|
7993
|
+
parts.push('<title>' + safeTitle + '</title>');
|
|
7994
|
+
if (faviconTag) parts.push(faviconTag);
|
|
7995
|
+
if (runtimeHead) parts.push(runtimeHead);
|
|
7996
|
+
if (headHTML) parts.push(headHTML);
|
|
7997
|
+
if (allCSS) parts.push('<style>' + allCSS + '</style>');
|
|
7998
|
+
parts.push('</head>');
|
|
7999
|
+
parts.push('<body>');
|
|
8000
|
+
parts.push(bodyHTML);
|
|
8001
|
+
if (bodyEndScript) parts.push(bodyEndScript);
|
|
8002
|
+
parts.push('</body>');
|
|
8003
|
+
parts.push('</html>');
|
|
8004
|
+
|
|
8005
|
+
return parts.join('\n');
|
|
8006
|
+
};
|
|
8007
|
+
|
|
7476
8008
|
/**
|
|
7477
8009
|
* Create a live DOM element from a TACO object (browser only).
|
|
7478
8010
|
*
|
|
@@ -7517,7 +8049,7 @@
|
|
|
7517
8049
|
}
|
|
7518
8050
|
|
|
7519
8051
|
// Handle text nodes
|
|
7520
|
-
if (
|
|
8052
|
+
if (!_is(taco, 'object') || !taco.t) {
|
|
7521
8053
|
return document.createTextNode(String(taco));
|
|
7522
8054
|
}
|
|
7523
8055
|
|
|
@@ -7530,16 +8062,16 @@
|
|
|
7530
8062
|
for (const [key, value] of Object.entries(attrs)) {
|
|
7531
8063
|
if (value == null || value === false) continue;
|
|
7532
8064
|
|
|
7533
|
-
if (key === 'style' &&
|
|
8065
|
+
if (key === 'style' && _is(value, 'object')) {
|
|
7534
8066
|
// Apply styles directly
|
|
7535
8067
|
Object.assign(el.style, value);
|
|
7536
8068
|
} else if (key === 'class') {
|
|
7537
8069
|
// Handle class as array or string
|
|
7538
|
-
const classStr =
|
|
8070
|
+
const classStr = _isA(value) ? value.filter(Boolean).join(' ') : String(value);
|
|
7539
8071
|
if (classStr) {
|
|
7540
8072
|
el.className = classStr;
|
|
7541
8073
|
}
|
|
7542
|
-
} else if (key.startsWith('on') &&
|
|
8074
|
+
} else if (key.startsWith('on') && _is(value, 'function')) {
|
|
7543
8075
|
// Event handlers
|
|
7544
8076
|
const eventName = key.slice(2).toLowerCase();
|
|
7545
8077
|
el.addEventListener(eventName, value);
|
|
@@ -7559,7 +8091,7 @@
|
|
|
7559
8091
|
// Children with data-bw_id or id attributes get local refs on the parent,
|
|
7560
8092
|
// so o.render functions can access them without any DOM lookup.
|
|
7561
8093
|
if (content != null) {
|
|
7562
|
-
if (
|
|
8094
|
+
if (_isA(content)) {
|
|
7563
8095
|
content.forEach(child => {
|
|
7564
8096
|
if (child != null) {
|
|
7565
8097
|
// Handle ComponentHandle in content arrays (Level 2 children)
|
|
@@ -7579,20 +8111,20 @@
|
|
|
7579
8111
|
if (childEl._bw_refs) {
|
|
7580
8112
|
if (!el._bw_refs) el._bw_refs = {};
|
|
7581
8113
|
for (var rk in childEl._bw_refs) {
|
|
7582
|
-
if (
|
|
8114
|
+
if (_hop.call(childEl._bw_refs, rk)) {
|
|
7583
8115
|
el._bw_refs[rk] = childEl._bw_refs[rk];
|
|
7584
8116
|
}
|
|
7585
8117
|
}
|
|
7586
8118
|
}
|
|
7587
8119
|
}
|
|
7588
8120
|
});
|
|
7589
|
-
} else if (
|
|
8121
|
+
} else if (_is(content, 'object') && content.__bw_raw) {
|
|
7590
8122
|
// Raw HTML content — inject via innerHTML
|
|
7591
8123
|
el.innerHTML = content.v;
|
|
7592
8124
|
} else if (content._bwComponent === true) {
|
|
7593
8125
|
// Single ComponentHandle as content
|
|
7594
8126
|
content.mount(el);
|
|
7595
|
-
} else if (
|
|
8127
|
+
} else if (_is(content, 'object') && content.t) {
|
|
7596
8128
|
var childEl = bw.createDOM(content, options);
|
|
7597
8129
|
el.appendChild(childEl);
|
|
7598
8130
|
var childBwId = content.a ? (content.a['data-bw_id'] || content.a.id) : null;
|
|
@@ -7603,7 +8135,7 @@
|
|
|
7603
8135
|
if (childEl._bw_refs) {
|
|
7604
8136
|
if (!el._bw_refs) el._bw_refs = {};
|
|
7605
8137
|
for (var rk in childEl._bw_refs) {
|
|
7606
|
-
if (
|
|
8138
|
+
if (_hop.call(childEl._bw_refs, rk)) {
|
|
7607
8139
|
el._bw_refs[rk] = childEl._bw_refs[rk];
|
|
7608
8140
|
}
|
|
7609
8141
|
}
|
|
@@ -7618,6 +8150,14 @@
|
|
|
7618
8150
|
bw._registerNode(el, null);
|
|
7619
8151
|
}
|
|
7620
8152
|
|
|
8153
|
+
// Register UUID class in node cache (bw_uuid_* tokens in class string)
|
|
8154
|
+
if (el.className) {
|
|
8155
|
+
var uuidMatch = el.className.match(_UUID_RE);
|
|
8156
|
+
if (uuidMatch) {
|
|
8157
|
+
bw._nodeMap[uuidMatch[0]] = el;
|
|
8158
|
+
}
|
|
8159
|
+
}
|
|
8160
|
+
|
|
7621
8161
|
// Handle lifecycle hooks and state
|
|
7622
8162
|
if (opts.mounted || opts.unmount || opts.render || opts.state) {
|
|
7623
8163
|
const id = attrs['data-bw_id'] || bw.uuid();
|
|
@@ -7636,7 +8176,7 @@
|
|
|
7636
8176
|
el._bw_render = opts.render;
|
|
7637
8177
|
|
|
7638
8178
|
if (opts.mounted) {
|
|
7639
|
-
|
|
8179
|
+
_cw('bw.createDOM: o.render and o.mounted are mutually exclusive. o.render wins.');
|
|
7640
8180
|
}
|
|
7641
8181
|
|
|
7642
8182
|
// Queue initial render (same timing as mounted)
|
|
@@ -7709,7 +8249,7 @@
|
|
|
7709
8249
|
const targetEl = bw._el(target);
|
|
7710
8250
|
|
|
7711
8251
|
if (!targetEl) {
|
|
7712
|
-
|
|
8252
|
+
_ce('bw.DOM: Target element not found:', target);
|
|
7713
8253
|
return null;
|
|
7714
8254
|
}
|
|
7715
8255
|
|
|
@@ -7749,7 +8289,7 @@
|
|
|
7749
8289
|
targetEl.appendChild(taco.element);
|
|
7750
8290
|
}
|
|
7751
8291
|
// Handle arrays
|
|
7752
|
-
else if (
|
|
8292
|
+
else if (_isA(taco)) {
|
|
7753
8293
|
taco.forEach(t => {
|
|
7754
8294
|
if (t != null) {
|
|
7755
8295
|
if (t._bwComponent === true) {
|
|
@@ -7785,7 +8325,7 @@
|
|
|
7785
8325
|
bw.compileProps = function(handle, props = {}) {
|
|
7786
8326
|
const compiledProps = {};
|
|
7787
8327
|
|
|
7788
|
-
|
|
8328
|
+
_keys(props).forEach(key => {
|
|
7789
8329
|
// Create getter/setter for each prop
|
|
7790
8330
|
Object.defineProperty(compiledProps, key, {
|
|
7791
8331
|
get() {
|
|
@@ -7990,6 +8530,16 @@
|
|
|
7990
8530
|
bw.cleanup = function(element) {
|
|
7991
8531
|
if (!bw._isBrowser || !element) return;
|
|
7992
8532
|
|
|
8533
|
+
// Deregister UUID classes from node cache (element + descendants)
|
|
8534
|
+
// Covers elements that have UUID but no data-bw_id
|
|
8535
|
+
var selfUuidMatch = element.className && element.className.match(_UUID_RE);
|
|
8536
|
+
if (selfUuidMatch) delete bw._nodeMap[selfUuidMatch[0]];
|
|
8537
|
+
var uuidEls = element.querySelectorAll('[class*="bw_uuid_"]');
|
|
8538
|
+
uuidEls.forEach(function(uel) {
|
|
8539
|
+
var m = uel.className && uel.className.match(_UUID_RE);
|
|
8540
|
+
if (m) delete bw._nodeMap[m[0]];
|
|
8541
|
+
});
|
|
8542
|
+
|
|
7993
8543
|
// Find all elements with data-bw_id
|
|
7994
8544
|
const elements = element.querySelectorAll('[data-bw_id]');
|
|
7995
8545
|
|
|
@@ -8005,6 +8555,10 @@
|
|
|
8005
8555
|
// Deregister from node cache
|
|
8006
8556
|
bw._deregisterNode(el, id);
|
|
8007
8557
|
|
|
8558
|
+
// Deregister UUID class from node cache
|
|
8559
|
+
var uuidMatch = el.className && el.className.match(_UUID_RE);
|
|
8560
|
+
if (uuidMatch) delete bw._nodeMap[uuidMatch[0]];
|
|
8561
|
+
|
|
8008
8562
|
// Clean up pub/sub subscriptions tied to this element
|
|
8009
8563
|
if (el._bw_subs) {
|
|
8010
8564
|
el._bw_subs.forEach(function(unsub) { unsub(); });
|
|
@@ -8029,6 +8583,10 @@
|
|
|
8029
8583
|
// Deregister from node cache
|
|
8030
8584
|
bw._deregisterNode(element, id);
|
|
8031
8585
|
|
|
8586
|
+
// Deregister UUID class from node cache
|
|
8587
|
+
var elemUuidMatch = element.className && element.className.match(_UUID_RE);
|
|
8588
|
+
if (elemUuidMatch) delete bw._nodeMap[elemUuidMatch[0]];
|
|
8589
|
+
|
|
8032
8590
|
// Clean up pub/sub subscriptions tied to element itself
|
|
8033
8591
|
if (element._bw_subs) {
|
|
8034
8592
|
element._bw_subs.forEach(function(unsub) { unsub(); });
|
|
@@ -8103,17 +8661,17 @@
|
|
|
8103
8661
|
if (attr) {
|
|
8104
8662
|
// Patch an attribute
|
|
8105
8663
|
el.setAttribute(attr, String(content));
|
|
8106
|
-
} else if (
|
|
8664
|
+
} else if (_isA(content)) {
|
|
8107
8665
|
// Patch with array of children (strings and/or TACOs)
|
|
8108
8666
|
el.innerHTML = '';
|
|
8109
8667
|
content.forEach(function(item) {
|
|
8110
|
-
if (
|
|
8668
|
+
if (_is(item, 'string') || _is(item, 'number')) {
|
|
8111
8669
|
el.appendChild(document.createTextNode(String(item)));
|
|
8112
8670
|
} else if (item && item.t) {
|
|
8113
8671
|
el.appendChild(bw.createDOM(item));
|
|
8114
8672
|
}
|
|
8115
8673
|
});
|
|
8116
|
-
} else if (
|
|
8674
|
+
} else if (_is(content, 'object') && content.t) {
|
|
8117
8675
|
// Patch with a TACO — replace children
|
|
8118
8676
|
el.innerHTML = '';
|
|
8119
8677
|
el.appendChild(bw.createDOM(content));
|
|
@@ -8144,7 +8702,7 @@
|
|
|
8144
8702
|
bw.patchAll = function(patches) {
|
|
8145
8703
|
var results = {};
|
|
8146
8704
|
for (var id in patches) {
|
|
8147
|
-
if (
|
|
8705
|
+
if (_hop.call(patches, id)) {
|
|
8148
8706
|
results[id] = bw.patch(id, patches[id]);
|
|
8149
8707
|
}
|
|
8150
8708
|
}
|
|
@@ -8241,7 +8799,7 @@
|
|
|
8241
8799
|
snapshot[i].handler(detail);
|
|
8242
8800
|
called++;
|
|
8243
8801
|
} catch (err) {
|
|
8244
|
-
|
|
8802
|
+
_cw('bw.pub: subscriber error on topic "' + topic + '":', err);
|
|
8245
8803
|
}
|
|
8246
8804
|
}
|
|
8247
8805
|
return called;
|
|
@@ -8337,8 +8895,8 @@
|
|
|
8337
8895
|
* @see bw.funcGetDispatchStr
|
|
8338
8896
|
*/
|
|
8339
8897
|
bw.funcRegister = function(fn, name) {
|
|
8340
|
-
if (
|
|
8341
|
-
var fnID = (
|
|
8898
|
+
if (!_is(fn, 'function')) return '';
|
|
8899
|
+
var fnID = (_is(name, 'string') && name.length > 0) ? name : ('bw_fn_' + bw._fnIDCounter++);
|
|
8342
8900
|
bw._fnRegistry[fnID] = fn;
|
|
8343
8901
|
return fnID;
|
|
8344
8902
|
};
|
|
@@ -8357,7 +8915,7 @@
|
|
|
8357
8915
|
bw.funcGetById = function(name, errFn) {
|
|
8358
8916
|
name = String(name);
|
|
8359
8917
|
if (name in bw._fnRegistry) return bw._fnRegistry[name];
|
|
8360
|
-
return (
|
|
8918
|
+
return _is(errFn, 'function') ? errFn : function() { _cw('bw.funcGetById: unregistered fn "' + name + '"'); };
|
|
8361
8919
|
};
|
|
8362
8920
|
|
|
8363
8921
|
/**
|
|
@@ -8398,13 +8956,30 @@
|
|
|
8398
8956
|
bw.funcGetRegistry = function() {
|
|
8399
8957
|
var copy = {};
|
|
8400
8958
|
for (var k in bw._fnRegistry) {
|
|
8401
|
-
if (
|
|
8959
|
+
if (_hop.call(bw._fnRegistry, k)) {
|
|
8402
8960
|
copy[k] = bw._fnRegistry[k];
|
|
8403
8961
|
}
|
|
8404
8962
|
}
|
|
8405
8963
|
return copy;
|
|
8406
8964
|
};
|
|
8407
8965
|
|
|
8966
|
+
/**
|
|
8967
|
+
* Minimal runtime shim for funcRegister dispatch in static HTML.
|
|
8968
|
+
* When embedded in a `<script>` tag, provides just enough infrastructure
|
|
8969
|
+
* for `bw.funcGetById()` calls to resolve. The actual function bodies
|
|
8970
|
+
* are emitted separately as `bw._fnRegistry['bw_fn_X'] = ...;` assignments.
|
|
8971
|
+
* @type {string}
|
|
8972
|
+
* @category Function Registry
|
|
8973
|
+
*/
|
|
8974
|
+
bw._FUNC_REGISTRY_SHIM = '(function(){var bw=window.bw||(window.bw={});' +
|
|
8975
|
+
'if(!bw._fnRegistry)bw._fnRegistry={};' +
|
|
8976
|
+
'bw.funcGetById=function(n){return bw._fnRegistry[n]||function(){' +
|
|
8977
|
+
'console.warn("bw: unregistered fn "+n)};};' +
|
|
8978
|
+
'bw.funcRegister=function(fn,name){' +
|
|
8979
|
+
'var id=name||("bw_fn_"+(bw._fnIDCounter=(bw._fnIDCounter||0)+1));' +
|
|
8980
|
+
'bw._fnRegistry[id]=fn;return id;};' +
|
|
8981
|
+
'window.bw=bw;})();';
|
|
8982
|
+
|
|
8408
8983
|
// ===================================================================================
|
|
8409
8984
|
// Template Binding Utilities
|
|
8410
8985
|
// ===================================================================================
|
|
@@ -8432,7 +9007,10 @@
|
|
|
8432
9007
|
var parts = path.split('.');
|
|
8433
9008
|
var val = state;
|
|
8434
9009
|
for (var i = 0; i < parts.length; i++) {
|
|
8435
|
-
if (val == null)
|
|
9010
|
+
if (val == null) {
|
|
9011
|
+
if (bw.debug) _cw('bw.debug: _evaluatePath — null at key "' + parts[i] + '" in path "' + path + '"');
|
|
9012
|
+
return '';
|
|
9013
|
+
}
|
|
8436
9014
|
val = val[parts[i]];
|
|
8437
9015
|
}
|
|
8438
9016
|
return (val == null) ? '' : val;
|
|
@@ -8452,7 +9030,7 @@
|
|
|
8452
9030
|
*/
|
|
8453
9031
|
bw._compiledExprs = {};
|
|
8454
9032
|
bw._resolveTemplate = function(str, state, compile) {
|
|
8455
|
-
if (
|
|
9033
|
+
if (!_is(str, 'string') || str.indexOf('${') < 0) return str;
|
|
8456
9034
|
var bindings = bw._parseBindings(str);
|
|
8457
9035
|
if (bindings.length === 0) return str;
|
|
8458
9036
|
|
|
@@ -8474,6 +9052,7 @@
|
|
|
8474
9052
|
try {
|
|
8475
9053
|
val = bw._compiledExprs[b.expr](state);
|
|
8476
9054
|
} catch (e) {
|
|
9055
|
+
if (bw.debug) _cw('bw.debug: _resolveTemplate — Tier 2 eval failed for "${' + b.expr + '}":', e.message);
|
|
8477
9056
|
val = '';
|
|
8478
9057
|
}
|
|
8479
9058
|
} else {
|
|
@@ -8582,7 +9161,7 @@
|
|
|
8582
9161
|
this._state = {};
|
|
8583
9162
|
if (o.state) {
|
|
8584
9163
|
for (var k in o.state) {
|
|
8585
|
-
if (
|
|
9164
|
+
if (_hop.call(o.state, k)) {
|
|
8586
9165
|
this._state[k] = o.state[k];
|
|
8587
9166
|
}
|
|
8588
9167
|
}
|
|
@@ -8591,7 +9170,7 @@
|
|
|
8591
9170
|
this._actions = {};
|
|
8592
9171
|
if (o.actions) {
|
|
8593
9172
|
for (var k2 in o.actions) {
|
|
8594
|
-
if (
|
|
9173
|
+
if (_hop.call(o.actions, k2)) {
|
|
8595
9174
|
this._actions[k2] = o.actions[k2];
|
|
8596
9175
|
}
|
|
8597
9176
|
}
|
|
@@ -8601,7 +9180,7 @@
|
|
|
8601
9180
|
if (o.methods) {
|
|
8602
9181
|
var self = this;
|
|
8603
9182
|
for (var k3 in o.methods) {
|
|
8604
|
-
if (
|
|
9183
|
+
if (_hop.call(o.methods, k3)) {
|
|
8605
9184
|
this._methods[k3] = o.methods[k3];
|
|
8606
9185
|
(function(methodName, methodFn) {
|
|
8607
9186
|
self[methodName] = function() {
|
|
@@ -8619,7 +9198,7 @@
|
|
|
8619
9198
|
willMount: o.willMount || null,
|
|
8620
9199
|
mounted: o.mounted || null,
|
|
8621
9200
|
willUpdate: o.willUpdate || null,
|
|
8622
|
-
onUpdate: o.onUpdate || null,
|
|
9201
|
+
onUpdate: o.onUpdate || o.updated || null,
|
|
8623
9202
|
unmount: o.unmount || null,
|
|
8624
9203
|
willDestroy: o.willDestroy || null
|
|
8625
9204
|
};
|
|
@@ -8634,14 +9213,23 @@
|
|
|
8634
9213
|
this._compile = !!o.compile;
|
|
8635
9214
|
this._bw_refs = {};
|
|
8636
9215
|
this._refCounter = 0;
|
|
9216
|
+
// Child component ownership (Bug #5)
|
|
9217
|
+
this._children = [];
|
|
9218
|
+
this._parent = null;
|
|
9219
|
+
// Factory metadata for BCCL rebuild (Bug #6)
|
|
9220
|
+
this._factory = taco._bwFactory || null;
|
|
8637
9221
|
}
|
|
8638
9222
|
|
|
9223
|
+
// Short alias for ComponentHandle.prototype (see alias block at top of file).
|
|
9224
|
+
// 28 method definitions × 25 chars = ~700B raw savings in minified output.
|
|
9225
|
+
var _chp = ComponentHandle.prototype;
|
|
9226
|
+
|
|
8639
9227
|
// ── State Methods ──
|
|
8640
9228
|
|
|
8641
9229
|
/**
|
|
8642
9230
|
* Get a state value. Dot-path supported: `get('user.name')`
|
|
8643
9231
|
*/
|
|
8644
|
-
|
|
9232
|
+
_chp.get = function(key) {
|
|
8645
9233
|
return bw._evaluatePath(this._state, key);
|
|
8646
9234
|
};
|
|
8647
9235
|
|
|
@@ -8651,12 +9239,13 @@
|
|
|
8651
9239
|
* @param {*} value - New value
|
|
8652
9240
|
* @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
|
|
8653
9241
|
*/
|
|
8654
|
-
|
|
9242
|
+
_chp.set = function(key, value, opts) {
|
|
8655
9243
|
// Dot-path set
|
|
8656
9244
|
var parts = key.split('.');
|
|
8657
9245
|
var obj = this._state;
|
|
8658
9246
|
for (var i = 0; i < parts.length - 1; i++) {
|
|
8659
|
-
if (obj[parts[i]]
|
|
9247
|
+
if (!_is(obj[parts[i]], 'object')) {
|
|
9248
|
+
if (bw.debug) _cw('bw.debug: set() — auto-creating intermediate "' + parts[i] + '" in path "' + key + '"');
|
|
8660
9249
|
obj[parts[i]] = {};
|
|
8661
9250
|
}
|
|
8662
9251
|
obj = obj[parts[i]];
|
|
@@ -8676,10 +9265,10 @@
|
|
|
8676
9265
|
/**
|
|
8677
9266
|
* Get a shallow clone of the full state.
|
|
8678
9267
|
*/
|
|
8679
|
-
|
|
9268
|
+
_chp.getState = function() {
|
|
8680
9269
|
var clone = {};
|
|
8681
9270
|
for (var k in this._state) {
|
|
8682
|
-
if (
|
|
9271
|
+
if (_hop.call(this._state, k)) {
|
|
8683
9272
|
clone[k] = this._state[k];
|
|
8684
9273
|
}
|
|
8685
9274
|
}
|
|
@@ -8691,9 +9280,9 @@
|
|
|
8691
9280
|
* @param {Object} updates - Key-value pairs to merge
|
|
8692
9281
|
* @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
|
|
8693
9282
|
*/
|
|
8694
|
-
|
|
9283
|
+
_chp.setState = function(updates, opts) {
|
|
8695
9284
|
for (var k in updates) {
|
|
8696
|
-
if (
|
|
9285
|
+
if (_hop.call(updates, k)) {
|
|
8697
9286
|
this._state[k] = updates[k];
|
|
8698
9287
|
this._dirtyKeys[k] = true;
|
|
8699
9288
|
}
|
|
@@ -8710,9 +9299,9 @@
|
|
|
8710
9299
|
/**
|
|
8711
9300
|
* Push a value onto an array in state. Clones the array.
|
|
8712
9301
|
*/
|
|
8713
|
-
|
|
9302
|
+
_chp.push = function(key, val) {
|
|
8714
9303
|
var arr = this.get(key);
|
|
8715
|
-
var newArr =
|
|
9304
|
+
var newArr = _isA(arr) ? arr.slice() : [];
|
|
8716
9305
|
newArr.push(val);
|
|
8717
9306
|
this.set(key, newArr);
|
|
8718
9307
|
};
|
|
@@ -8720,9 +9309,9 @@
|
|
|
8720
9309
|
/**
|
|
8721
9310
|
* Splice an array in state. Clones the array.
|
|
8722
9311
|
*/
|
|
8723
|
-
|
|
9312
|
+
_chp.splice = function(key, start, deleteCount) {
|
|
8724
9313
|
var arr = this.get(key);
|
|
8725
|
-
var newArr =
|
|
9314
|
+
var newArr = _isA(arr) ? arr.slice() : [];
|
|
8726
9315
|
var args = [start, deleteCount].concat(Array.prototype.slice.call(arguments, 3));
|
|
8727
9316
|
Array.prototype.splice.apply(newArr, args);
|
|
8728
9317
|
this.set(key, newArr);
|
|
@@ -8730,7 +9319,7 @@
|
|
|
8730
9319
|
|
|
8731
9320
|
// ── Scheduling ──
|
|
8732
9321
|
|
|
8733
|
-
|
|
9322
|
+
_chp._scheduleDirty = function() {
|
|
8734
9323
|
if (!this._scheduled) {
|
|
8735
9324
|
this._scheduled = true;
|
|
8736
9325
|
bw._dirtyComponents.push(this);
|
|
@@ -8745,17 +9334,17 @@
|
|
|
8745
9334
|
* Creates binding descriptors with refIds for targeted DOM updates.
|
|
8746
9335
|
* @private
|
|
8747
9336
|
*/
|
|
8748
|
-
|
|
9337
|
+
_chp._compileBindings = function() {
|
|
8749
9338
|
this._bindings = [];
|
|
8750
9339
|
this._refCounter = 0;
|
|
8751
|
-
var stateKeys =
|
|
9340
|
+
var stateKeys = _keys(this._state);
|
|
8752
9341
|
var self = this;
|
|
8753
9342
|
|
|
8754
9343
|
function walkTaco(taco, path) {
|
|
8755
|
-
if (taco
|
|
9344
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
8756
9345
|
|
|
8757
9346
|
// Check content for bindings
|
|
8758
|
-
if (
|
|
9347
|
+
if (_is(taco.c, 'string') && taco.c.indexOf('${') >= 0) {
|
|
8759
9348
|
var refId = 'bw_ref_' + self._refCounter++;
|
|
8760
9349
|
var parsed = bw._parseBindings(taco.c);
|
|
8761
9350
|
var deps = [];
|
|
@@ -8777,10 +9366,10 @@
|
|
|
8777
9366
|
// Check attributes for bindings
|
|
8778
9367
|
if (taco.a) {
|
|
8779
9368
|
for (var attrName in taco.a) {
|
|
8780
|
-
if (!
|
|
9369
|
+
if (!_hop.call(taco.a, attrName)) continue;
|
|
8781
9370
|
if (attrName === 'data-bw_ref') continue;
|
|
8782
9371
|
var attrVal = taco.a[attrName];
|
|
8783
|
-
if (
|
|
9372
|
+
if (_is(attrVal, 'string') && attrVal.indexOf('${') >= 0) {
|
|
8784
9373
|
var refId2 = 'bw_ref_' + self._refCounter++;
|
|
8785
9374
|
var parsed2 = bw._parseBindings(attrVal);
|
|
8786
9375
|
var deps2 = [];
|
|
@@ -8806,9 +9395,27 @@
|
|
|
8806
9395
|
}
|
|
8807
9396
|
|
|
8808
9397
|
// Recurse into children
|
|
8809
|
-
if (
|
|
9398
|
+
if (_isA(taco.c)) {
|
|
8810
9399
|
for (var i = 0; i < taco.c.length; i++) {
|
|
8811
|
-
|
|
9400
|
+
// Wrap string children with ${expr} in a span so patches target the span, not the parent
|
|
9401
|
+
if (_is(taco.c[i], 'string') && taco.c[i].indexOf('${') >= 0) {
|
|
9402
|
+
var mixedRefId = 'bw_ref_' + self._refCounter++;
|
|
9403
|
+
var mixedParsed = bw._parseBindings(taco.c[i]);
|
|
9404
|
+
var mixedDeps = [];
|
|
9405
|
+
for (var mi = 0; mi < mixedParsed.length; mi++) {
|
|
9406
|
+
mixedDeps = mixedDeps.concat(bw._extractDeps(mixedParsed[mi].expr, stateKeys));
|
|
9407
|
+
}
|
|
9408
|
+
self._bindings.push({
|
|
9409
|
+
expr: taco.c[i],
|
|
9410
|
+
type: 'content',
|
|
9411
|
+
refId: mixedRefId,
|
|
9412
|
+
deps: mixedDeps,
|
|
9413
|
+
template: taco.c[i]
|
|
9414
|
+
});
|
|
9415
|
+
// Replace string with a span wrapper so textContent targets the span only
|
|
9416
|
+
taco.c[i] = { t: 'span', a: { 'data-bw_ref': mixedRefId, style: 'display:contents' }, c: taco.c[i] };
|
|
9417
|
+
}
|
|
9418
|
+
if (_is(taco.c[i], 'object') && taco.c[i].t) {
|
|
8812
9419
|
walkTaco(taco.c[i], path.concat(i));
|
|
8813
9420
|
}
|
|
8814
9421
|
// Handle bw.when/bw.each markers
|
|
@@ -8843,7 +9450,7 @@
|
|
|
8843
9450
|
taco.c[i]._refId = eachRefId;
|
|
8844
9451
|
}
|
|
8845
9452
|
}
|
|
8846
|
-
} else if (taco.c
|
|
9453
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
8847
9454
|
walkTaco(taco.c, path.concat(0));
|
|
8848
9455
|
}
|
|
8849
9456
|
|
|
@@ -8859,7 +9466,7 @@
|
|
|
8859
9466
|
* Build ref map from the live DOM after createDOM.
|
|
8860
9467
|
* @private
|
|
8861
9468
|
*/
|
|
8862
|
-
|
|
9469
|
+
_chp._collectRefs = function() {
|
|
8863
9470
|
this._bw_refs = {};
|
|
8864
9471
|
if (!this.element) return;
|
|
8865
9472
|
var els = this.element.querySelectorAll('[data-bw_ref]');
|
|
@@ -8880,7 +9487,7 @@
|
|
|
8880
9487
|
* Creates DOM, compiles bindings, registers actions, and calls lifecycle hooks.
|
|
8881
9488
|
* @param {Element} parentEl - DOM element to mount into
|
|
8882
9489
|
*/
|
|
8883
|
-
|
|
9490
|
+
_chp.mount = function(parentEl) {
|
|
8884
9491
|
// willMount hook
|
|
8885
9492
|
if (this._hooks.willMount) this._hooks.willMount(this);
|
|
8886
9493
|
|
|
@@ -8902,7 +9509,7 @@
|
|
|
8902
9509
|
// Register named actions in function registry
|
|
8903
9510
|
var self = this;
|
|
8904
9511
|
for (var actionName in this._actions) {
|
|
8905
|
-
if (
|
|
9512
|
+
if (_hop.call(this._actions, actionName)) {
|
|
8906
9513
|
var registeredName = this._bwId + '_' + actionName;
|
|
8907
9514
|
(function(aName) {
|
|
8908
9515
|
bw.funcRegister(function(evt) {
|
|
@@ -8921,6 +9528,11 @@
|
|
|
8921
9528
|
this.element = bw.createDOM(tacoForDOM);
|
|
8922
9529
|
this.element._bwComponentHandle = this;
|
|
8923
9530
|
this.element.setAttribute('data-bw_comp_id', this._bwId);
|
|
9531
|
+
|
|
9532
|
+
// Restore o.render from original TACO (stripped by _tacoForDOM)
|
|
9533
|
+
if (this.taco.o && this.taco.o.render) {
|
|
9534
|
+
this.element._bw_render = this.taco.o.render;
|
|
9535
|
+
}
|
|
8924
9536
|
if (this._userTag) {
|
|
8925
9537
|
this.element.classList.add(this._userTag);
|
|
8926
9538
|
}
|
|
@@ -8936,6 +9548,16 @@
|
|
|
8936
9548
|
|
|
8937
9549
|
this.mounted = true;
|
|
8938
9550
|
|
|
9551
|
+
// Scan for child ComponentHandles and link parent/child (Bug #5)
|
|
9552
|
+
var childEls = this.element.querySelectorAll('[data-bw_comp_id]');
|
|
9553
|
+
for (var ci = 0; ci < childEls.length; ci++) {
|
|
9554
|
+
var ch = childEls[ci]._bwComponentHandle;
|
|
9555
|
+
if (ch && ch !== this && !ch._parent) {
|
|
9556
|
+
ch._parent = this;
|
|
9557
|
+
this._children.push(ch);
|
|
9558
|
+
}
|
|
9559
|
+
}
|
|
9560
|
+
|
|
8939
9561
|
// mounted hook (backward compat: fn.length === 2 wraps (el, state))
|
|
8940
9562
|
if (this._hooks.mounted) {
|
|
8941
9563
|
if (this._hooks.mounted.length === 2) {
|
|
@@ -8944,16 +9566,21 @@
|
|
|
8944
9566
|
this._hooks.mounted(this);
|
|
8945
9567
|
}
|
|
8946
9568
|
}
|
|
9569
|
+
|
|
9570
|
+
// Invoke o.render on initial mount (if present)
|
|
9571
|
+
if (this.element._bw_render) {
|
|
9572
|
+
this.element._bw_render(this.element, this._state);
|
|
9573
|
+
}
|
|
8947
9574
|
};
|
|
8948
9575
|
|
|
8949
9576
|
/**
|
|
8950
9577
|
* Prepare TACO for initial render: resolve when/each markers.
|
|
8951
9578
|
* @private
|
|
8952
9579
|
*/
|
|
8953
|
-
|
|
8954
|
-
if (!taco
|
|
9580
|
+
_chp._prepareTaco = function(taco) {
|
|
9581
|
+
if (!_is(taco, 'object')) return;
|
|
8955
9582
|
|
|
8956
|
-
if (
|
|
9583
|
+
if (_isA(taco.c)) {
|
|
8957
9584
|
for (var i = taco.c.length - 1; i >= 0; i--) {
|
|
8958
9585
|
var child = taco.c[i];
|
|
8959
9586
|
if (child && child._bwWhen) {
|
|
@@ -8978,18 +9605,18 @@
|
|
|
8978
9605
|
var eachExprStr = child.expr.replace(/^\$\{|\}$/g, '');
|
|
8979
9606
|
var arr = bw._evaluatePath(this._state, eachExprStr);
|
|
8980
9607
|
var items = [];
|
|
8981
|
-
if (
|
|
9608
|
+
if (_isA(arr)) {
|
|
8982
9609
|
for (var j = 0; j < arr.length; j++) {
|
|
8983
9610
|
items.push(child.factory(arr[j], j));
|
|
8984
9611
|
}
|
|
8985
9612
|
}
|
|
8986
9613
|
taco.c[i] = { t: 'span', a: { 'data-bw_each': child._refId, style: 'display:contents' }, c: items };
|
|
8987
9614
|
}
|
|
8988
|
-
if (taco.c[i]
|
|
9615
|
+
if (_is(taco.c[i], 'object') && taco.c[i].t) {
|
|
8989
9616
|
this._prepareTaco(taco.c[i]);
|
|
8990
9617
|
}
|
|
8991
9618
|
}
|
|
8992
|
-
} else if (taco.c
|
|
9619
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
8993
9620
|
this._prepareTaco(taco.c);
|
|
8994
9621
|
}
|
|
8995
9622
|
};
|
|
@@ -8998,12 +9625,12 @@
|
|
|
8998
9625
|
* Wire action name strings (in onclick etc.) to dispatch function calls.
|
|
8999
9626
|
* @private
|
|
9000
9627
|
*/
|
|
9001
|
-
|
|
9002
|
-
if (!taco
|
|
9628
|
+
_chp._wireActions = function(taco) {
|
|
9629
|
+
if (!_is(taco, 'object') || !taco.t) return;
|
|
9003
9630
|
if (taco.a) {
|
|
9004
9631
|
for (var key in taco.a) {
|
|
9005
|
-
if (!
|
|
9006
|
-
if (key.startsWith('on') &&
|
|
9632
|
+
if (!_hop.call(taco.a, key)) continue;
|
|
9633
|
+
if (key.startsWith('on') && _is(taco.a[key], 'string')) {
|
|
9007
9634
|
var actionName = taco.a[key];
|
|
9008
9635
|
if (actionName in this._actions) {
|
|
9009
9636
|
var registeredName = this._bwId + '_' + actionName;
|
|
@@ -9017,11 +9644,11 @@
|
|
|
9017
9644
|
}
|
|
9018
9645
|
}
|
|
9019
9646
|
}
|
|
9020
|
-
if (
|
|
9647
|
+
if (_isA(taco.c)) {
|
|
9021
9648
|
for (var i = 0; i < taco.c.length; i++) {
|
|
9022
9649
|
this._wireActions(taco.c[i]);
|
|
9023
9650
|
}
|
|
9024
|
-
} else if (taco.c
|
|
9651
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
9025
9652
|
this._wireActions(taco.c);
|
|
9026
9653
|
}
|
|
9027
9654
|
};
|
|
@@ -9030,7 +9657,7 @@
|
|
|
9030
9657
|
* Deep-clone a TACO tree, preserving _bwWhen/_bwEach markers and their factories.
|
|
9031
9658
|
* @private
|
|
9032
9659
|
*/
|
|
9033
|
-
|
|
9660
|
+
_chp._deepCloneTaco = function(taco) {
|
|
9034
9661
|
if (taco == null) return taco;
|
|
9035
9662
|
// Preserve _bwWhen / _bwEach markers (contain functions)
|
|
9036
9663
|
if (taco._bwWhen) {
|
|
@@ -9042,18 +9669,18 @@
|
|
|
9042
9669
|
if (taco._bwEach) {
|
|
9043
9670
|
return { _bwEach: true, expr: taco.expr, factory: taco.factory, _refId: taco._refId };
|
|
9044
9671
|
}
|
|
9045
|
-
if (
|
|
9672
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
9046
9673
|
var result = { t: taco.t };
|
|
9047
9674
|
if (taco.a) {
|
|
9048
9675
|
result.a = {};
|
|
9049
9676
|
for (var k in taco.a) {
|
|
9050
|
-
if (
|
|
9677
|
+
if (_hop.call(taco.a, k)) result.a[k] = taco.a[k];
|
|
9051
9678
|
}
|
|
9052
9679
|
}
|
|
9053
9680
|
if (taco.c != null) {
|
|
9054
|
-
if (
|
|
9681
|
+
if (_isA(taco.c)) {
|
|
9055
9682
|
result.c = taco.c.map(function(child) { return this._deepCloneTaco(child); }.bind(this));
|
|
9056
|
-
} else if (
|
|
9683
|
+
} else if (_is(taco.c, 'object')) {
|
|
9057
9684
|
result.c = this._deepCloneTaco(taco.c);
|
|
9058
9685
|
} else {
|
|
9059
9686
|
result.c = taco.c;
|
|
@@ -9067,27 +9694,31 @@
|
|
|
9067
9694
|
* Create a copy of TACO suitable for createDOM (strips o to prevent double lifecycle).
|
|
9068
9695
|
* @private
|
|
9069
9696
|
*/
|
|
9070
|
-
|
|
9071
|
-
if (!taco
|
|
9697
|
+
_chp._tacoForDOM = function(taco) {
|
|
9698
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
9072
9699
|
var result = { t: taco.t };
|
|
9073
9700
|
if (taco.a) result.a = taco.a;
|
|
9074
9701
|
if (taco.c != null) {
|
|
9075
|
-
if (
|
|
9702
|
+
if (_isA(taco.c)) {
|
|
9076
9703
|
result.c = taco.c.map(function(child) { return this._tacoForDOM(child); }.bind(this));
|
|
9077
|
-
} else if (
|
|
9704
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
9078
9705
|
result.c = this._tacoForDOM(taco.c);
|
|
9079
9706
|
} else {
|
|
9080
9707
|
result.c = taco.c;
|
|
9081
9708
|
}
|
|
9082
9709
|
}
|
|
9083
9710
|
// Intentionally strip o (no mounted/unmount/state/render on sub-elements)
|
|
9711
|
+
if (taco.o && (taco.o.mounted || taco.o.render || taco.o.unmount)) {
|
|
9712
|
+
_cw('bw: _tacoForDOM stripped o.mounted/render/unmount from child <' + taco.t +
|
|
9713
|
+
'>. Use onclick attribute or bw.component() for child interactivity.');
|
|
9714
|
+
}
|
|
9084
9715
|
return result;
|
|
9085
9716
|
};
|
|
9086
9717
|
|
|
9087
9718
|
/**
|
|
9088
9719
|
* Unmount: remove from DOM, deactivate, preserve state for re-mount.
|
|
9089
9720
|
*/
|
|
9090
|
-
|
|
9721
|
+
_chp.unmount = function() {
|
|
9091
9722
|
if (!this.mounted) return;
|
|
9092
9723
|
|
|
9093
9724
|
// unmount hook
|
|
@@ -9122,12 +9753,23 @@
|
|
|
9122
9753
|
/**
|
|
9123
9754
|
* Destroy: unmount + clear state + unregister actions.
|
|
9124
9755
|
*/
|
|
9125
|
-
|
|
9756
|
+
_chp.destroy = function() {
|
|
9126
9757
|
// willDestroy hook
|
|
9127
9758
|
if (this._hooks.willDestroy) {
|
|
9128
9759
|
this._hooks.willDestroy(this);
|
|
9129
9760
|
}
|
|
9130
9761
|
|
|
9762
|
+
// Cascade destroy to children depth-first (Bug #5)
|
|
9763
|
+
for (var ci = this._children.length - 1; ci >= 0; ci--) {
|
|
9764
|
+
this._children[ci].destroy();
|
|
9765
|
+
}
|
|
9766
|
+
this._children = [];
|
|
9767
|
+
if (this._parent) {
|
|
9768
|
+
var idx = this._parent._children.indexOf(this);
|
|
9769
|
+
if (idx >= 0) this._parent._children.splice(idx, 1);
|
|
9770
|
+
this._parent = null;
|
|
9771
|
+
}
|
|
9772
|
+
|
|
9131
9773
|
this.unmount();
|
|
9132
9774
|
|
|
9133
9775
|
// Unregister actions from function registry
|
|
@@ -9154,12 +9796,36 @@
|
|
|
9154
9796
|
* Flush dirty state: resolve changed bindings and apply to DOM.
|
|
9155
9797
|
* @private
|
|
9156
9798
|
*/
|
|
9157
|
-
|
|
9799
|
+
_chp._flush = function() {
|
|
9158
9800
|
this._scheduled = false;
|
|
9159
|
-
var changedKeys =
|
|
9801
|
+
var changedKeys = _keys(this._dirtyKeys);
|
|
9160
9802
|
this._dirtyKeys = {};
|
|
9161
9803
|
if (changedKeys.length === 0 || !this.mounted) return;
|
|
9162
9804
|
|
|
9805
|
+
// Factory rebuild: if a BCCL factory exists and changed keys overlap factory props,
|
|
9806
|
+
// rebuild the TACO from the factory with merged state (Bug #6)
|
|
9807
|
+
if (this._factory) {
|
|
9808
|
+
var rebuildNeeded = false;
|
|
9809
|
+
for (var fi = 0; fi < changedKeys.length; fi++) {
|
|
9810
|
+
if (_hop.call(this._factory.props, changedKeys[fi])) {
|
|
9811
|
+
rebuildNeeded = true; break;
|
|
9812
|
+
}
|
|
9813
|
+
}
|
|
9814
|
+
if (rebuildNeeded) {
|
|
9815
|
+
var merged = {};
|
|
9816
|
+
for (var mk in this._factory.props) if (_hop.call(this._factory.props, mk)) merged[mk] = this._factory.props[mk];
|
|
9817
|
+
for (var sk in this._state) if (_hop.call(this._state, sk)) merged[sk] = this._state[sk];
|
|
9818
|
+
this._factory.props = merged;
|
|
9819
|
+
var newTaco = bw.make(this._factory.type, merged);
|
|
9820
|
+
newTaco._bwFactory = this._factory;
|
|
9821
|
+
this.taco = newTaco;
|
|
9822
|
+
this._originalTaco = this._deepCloneTaco(newTaco);
|
|
9823
|
+
this._render();
|
|
9824
|
+
if (this._hooks.onUpdate) this._hooks.onUpdate(this, changedKeys);
|
|
9825
|
+
return;
|
|
9826
|
+
}
|
|
9827
|
+
}
|
|
9828
|
+
|
|
9163
9829
|
// willUpdate hook
|
|
9164
9830
|
if (this._hooks.willUpdate) {
|
|
9165
9831
|
this._hooks.willUpdate(this, changedKeys);
|
|
@@ -9198,7 +9864,7 @@
|
|
|
9198
9864
|
* Returns list of patches to apply.
|
|
9199
9865
|
* @private
|
|
9200
9866
|
*/
|
|
9201
|
-
|
|
9867
|
+
_chp._resolveBindings = function(changedKeys) {
|
|
9202
9868
|
var patches = [];
|
|
9203
9869
|
for (var i = 0; i < this._bindings.length; i++) {
|
|
9204
9870
|
var b = this._bindings[i];
|
|
@@ -9234,11 +9900,14 @@
|
|
|
9234
9900
|
* Apply patches to DOM.
|
|
9235
9901
|
* @private
|
|
9236
9902
|
*/
|
|
9237
|
-
|
|
9903
|
+
_chp._applyPatches = function(patches) {
|
|
9238
9904
|
for (var i = 0; i < patches.length; i++) {
|
|
9239
9905
|
var p = patches[i];
|
|
9240
9906
|
var el = this._bw_refs[p.refId];
|
|
9241
|
-
if (!el)
|
|
9907
|
+
if (!el) {
|
|
9908
|
+
if (bw.debug) _cw('bw.debug: _applyPatches — ref "' + p.refId + '" not found in DOM');
|
|
9909
|
+
continue;
|
|
9910
|
+
}
|
|
9242
9911
|
if (p.type === 'content') {
|
|
9243
9912
|
el.textContent = p.value;
|
|
9244
9913
|
} else if (p.type === 'attribute') {
|
|
@@ -9255,7 +9924,7 @@
|
|
|
9255
9924
|
* Resolve all bindings and apply (used for initial render).
|
|
9256
9925
|
* @private
|
|
9257
9926
|
*/
|
|
9258
|
-
|
|
9927
|
+
_chp._resolveAndApplyAll = function() {
|
|
9259
9928
|
var patches = [];
|
|
9260
9929
|
for (var i = 0; i < this._bindings.length; i++) {
|
|
9261
9930
|
var b = this._bindings[i];
|
|
@@ -9278,7 +9947,7 @@
|
|
|
9278
9947
|
* Full re-render for structural changes (when/each branch switches).
|
|
9279
9948
|
* @private
|
|
9280
9949
|
*/
|
|
9281
|
-
|
|
9950
|
+
_chp._render = function() {
|
|
9282
9951
|
if (!this.element || !this.element.parentNode) return;
|
|
9283
9952
|
var parent = this.element.parentNode;
|
|
9284
9953
|
var nextSibling = this.element.nextSibling;
|
|
@@ -9318,7 +9987,7 @@
|
|
|
9318
9987
|
* @param {string} event - Event name (e.g., 'click')
|
|
9319
9988
|
* @param {Function} handler - Event handler
|
|
9320
9989
|
*/
|
|
9321
|
-
|
|
9990
|
+
_chp.on = function(event, handler) {
|
|
9322
9991
|
if (this.element) {
|
|
9323
9992
|
this.element.addEventListener(event, handler);
|
|
9324
9993
|
}
|
|
@@ -9330,7 +9999,7 @@
|
|
|
9330
9999
|
* @param {string} event - Event name
|
|
9331
10000
|
* @param {Function} handler - Handler to remove
|
|
9332
10001
|
*/
|
|
9333
|
-
|
|
10002
|
+
_chp.off = function(event, handler) {
|
|
9334
10003
|
if (this.element) {
|
|
9335
10004
|
this.element.removeEventListener(event, handler);
|
|
9336
10005
|
}
|
|
@@ -9345,7 +10014,7 @@
|
|
|
9345
10014
|
* @param {Function} handler - Handler function
|
|
9346
10015
|
* @returns {Function} Unsubscribe function
|
|
9347
10016
|
*/
|
|
9348
|
-
|
|
10017
|
+
_chp.sub = function(topic, handler) {
|
|
9349
10018
|
var unsub = bw.sub(topic, handler);
|
|
9350
10019
|
this._subs.push(unsub);
|
|
9351
10020
|
return unsub;
|
|
@@ -9356,10 +10025,10 @@
|
|
|
9356
10025
|
* @param {string} name - Action name
|
|
9357
10026
|
* @param {...*} args - Arguments passed after comp
|
|
9358
10027
|
*/
|
|
9359
|
-
|
|
10028
|
+
_chp.action = function(name) {
|
|
9360
10029
|
var fn = this._actions[name];
|
|
9361
10030
|
if (!fn) {
|
|
9362
|
-
|
|
10031
|
+
_cw('ComponentHandle.action: unknown action "' + name + '"');
|
|
9363
10032
|
return;
|
|
9364
10033
|
}
|
|
9365
10034
|
var args = [this].concat(Array.prototype.slice.call(arguments, 1));
|
|
@@ -9371,7 +10040,7 @@
|
|
|
9371
10040
|
* @param {string} sel - CSS selector
|
|
9372
10041
|
* @returns {Element|null}
|
|
9373
10042
|
*/
|
|
9374
|
-
|
|
10043
|
+
_chp.select = function(sel) {
|
|
9375
10044
|
return this.element ? this.element.querySelector(sel) : null;
|
|
9376
10045
|
};
|
|
9377
10046
|
|
|
@@ -9380,7 +10049,7 @@
|
|
|
9380
10049
|
* @param {string} sel - CSS selector
|
|
9381
10050
|
* @returns {Element[]}
|
|
9382
10051
|
*/
|
|
9383
|
-
|
|
10052
|
+
_chp.selectAll = function(sel) {
|
|
9384
10053
|
if (!this.element) return [];
|
|
9385
10054
|
return Array.prototype.slice.call(this.element.querySelectorAll(sel));
|
|
9386
10055
|
};
|
|
@@ -9391,7 +10060,7 @@
|
|
|
9391
10060
|
* @param {string} tag - User-defined identifier (e.g. 'dashboard_prod_east')
|
|
9392
10061
|
* @returns {ComponentHandle} this (for chaining)
|
|
9393
10062
|
*/
|
|
9394
|
-
|
|
10063
|
+
_chp.userTag = function(tag) {
|
|
9395
10064
|
this._userTag = tag;
|
|
9396
10065
|
if (this.element) {
|
|
9397
10066
|
this.element.classList.add(tag);
|
|
@@ -9468,7 +10137,7 @@
|
|
|
9468
10137
|
* and calls the named method. This is the bitwrench equivalent of
|
|
9469
10138
|
* Win32 SendMessage(hwnd, msg, wParam, lParam).
|
|
9470
10139
|
*
|
|
9471
|
-
* @param {string} target - Component UUID (data-bw_comp_id) or user tag (CSS class)
|
|
10140
|
+
* @param {string} target - Component UUID (bw_uuid_*), comp ID (data-bw_comp_id), or user tag (CSS class)
|
|
9472
10141
|
* @param {string} action - Method name to call on the component
|
|
9473
10142
|
* @param {*} data - Data to pass to the method
|
|
9474
10143
|
* @returns {boolean} True if message was dispatched successfully
|
|
@@ -9485,15 +10154,20 @@
|
|
|
9485
10154
|
* };
|
|
9486
10155
|
*/
|
|
9487
10156
|
bw.message = function(target, action, data) {
|
|
9488
|
-
// Try
|
|
9489
|
-
var el = bw
|
|
9490
|
-
|
|
10157
|
+
// Try bw._el() first (handles UUID class, nodeMap cache, getElementById)
|
|
10158
|
+
var el = bw._el(target);
|
|
10159
|
+
// Then try data-bw_comp_id attribute
|
|
10160
|
+
if (!el || !el._bwComponentHandle) {
|
|
10161
|
+
el = bw.$('[data-bw_comp_id="' + target + '"]')[0];
|
|
10162
|
+
}
|
|
10163
|
+
// Then try CSS class (user tag)
|
|
10164
|
+
if (!el || !el._bwComponentHandle) {
|
|
9491
10165
|
el = bw.$('.' + target)[0];
|
|
9492
10166
|
}
|
|
9493
10167
|
if (!el || !el._bwComponentHandle) return false;
|
|
9494
10168
|
var comp = el._bwComponentHandle;
|
|
9495
|
-
if (
|
|
9496
|
-
|
|
10169
|
+
if (!_is(comp[action], 'function')) {
|
|
10170
|
+
_cw('bw.message: unknown action "' + action + '" on component ' + target);
|
|
9497
10171
|
return false;
|
|
9498
10172
|
}
|
|
9499
10173
|
comp[action](data);
|
|
@@ -9501,59 +10175,24 @@
|
|
|
9501
10175
|
};
|
|
9502
10176
|
|
|
9503
10177
|
// ===================================================================================
|
|
9504
|
-
// bw.
|
|
10178
|
+
// bw.apply() / bw.parseJSONFlex() — Server-driven UI protocol
|
|
9505
10179
|
// ===================================================================================
|
|
9506
10180
|
|
|
9507
10181
|
/**
|
|
9508
10182
|
* Registry of named functions sent via register messages.
|
|
9509
|
-
* Populated by
|
|
9510
|
-
* Invoked by
|
|
10183
|
+
* Populated by bw.apply({ type: 'register', name, body }).
|
|
10184
|
+
* Invoked by bw.apply({ type: 'call', name, args }).
|
|
9511
10185
|
* @private
|
|
9512
10186
|
*/
|
|
9513
10187
|
bw._clientFunctions = {};
|
|
9514
10188
|
|
|
9515
10189
|
/**
|
|
9516
|
-
* Whether exec messages are allowed. Set by
|
|
10190
|
+
* Whether exec messages are allowed. Set by bwclient connect opts.allowExec.
|
|
9517
10191
|
* Default false — exec messages are rejected unless explicitly opted in.
|
|
9518
10192
|
* @private
|
|
9519
10193
|
*/
|
|
9520
10194
|
bw._allowExec = false;
|
|
9521
10195
|
|
|
9522
|
-
/**
|
|
9523
|
-
* Built-in client functions available via call() without registration.
|
|
9524
|
-
* @private
|
|
9525
|
-
*/
|
|
9526
|
-
bw._builtinClientFunctions = {
|
|
9527
|
-
scrollTo: function(selector) {
|
|
9528
|
-
var el = bw._el(selector);
|
|
9529
|
-
if (el) el.scrollTop = el.scrollHeight;
|
|
9530
|
-
},
|
|
9531
|
-
focus: function(selector) {
|
|
9532
|
-
var el = bw._el(selector);
|
|
9533
|
-
if (el && typeof el.focus === 'function') el.focus();
|
|
9534
|
-
},
|
|
9535
|
-
download: function(filename, content, mimeType) {
|
|
9536
|
-
if (typeof document === 'undefined') return;
|
|
9537
|
-
var blob = new Blob([content], { type: mimeType || 'text/plain' });
|
|
9538
|
-
var a = document.createElement('a');
|
|
9539
|
-
a.href = URL.createObjectURL(blob);
|
|
9540
|
-
a.download = filename;
|
|
9541
|
-
a.click();
|
|
9542
|
-
URL.revokeObjectURL(a.href);
|
|
9543
|
-
},
|
|
9544
|
-
clipboard: function(text) {
|
|
9545
|
-
if (typeof navigator !== 'undefined' && navigator.clipboard) {
|
|
9546
|
-
navigator.clipboard.writeText(text);
|
|
9547
|
-
}
|
|
9548
|
-
},
|
|
9549
|
-
redirect: function(url) {
|
|
9550
|
-
if (typeof window !== 'undefined') window.location.href = url;
|
|
9551
|
-
},
|
|
9552
|
-
log: function() {
|
|
9553
|
-
console.log.apply(console, arguments);
|
|
9554
|
-
}
|
|
9555
|
-
};
|
|
9556
|
-
|
|
9557
10196
|
/**
|
|
9558
10197
|
* Parse a bwserve protocol message string, supporting both strict JSON
|
|
9559
10198
|
* and r-prefixed relaxed JSON (single-quoted strings, trailing commas).
|
|
@@ -9568,9 +10207,9 @@
|
|
|
9568
10207
|
* @param {string} str - JSON or r-prefixed relaxed JSON string
|
|
9569
10208
|
* @returns {Object} Parsed message object
|
|
9570
10209
|
* @throws {SyntaxError} If the string is not valid JSON or relaxed JSON
|
|
9571
|
-
* @category
|
|
10210
|
+
* @category Core
|
|
9572
10211
|
*/
|
|
9573
|
-
bw.
|
|
10212
|
+
bw.parseJSONFlex = function(str) {
|
|
9574
10213
|
str = (str || '').trim();
|
|
9575
10214
|
if (str.charAt(0) !== 'r') return JSON.parse(str);
|
|
9576
10215
|
str = str.slice(1);
|
|
@@ -9655,10 +10294,10 @@
|
|
|
9655
10294
|
* append — target.appendChild(bw.createDOM(node))
|
|
9656
10295
|
* remove — bw.cleanup(target); target.remove()
|
|
9657
10296
|
* patch — bw.patch(target, content, attr)
|
|
9658
|
-
* batch — iterate ops, call
|
|
10297
|
+
* batch — iterate ops, call bw.apply for each
|
|
9659
10298
|
* message — bw.message(target, action, data)
|
|
9660
10299
|
* register — store a named function for later call()
|
|
9661
|
-
* call — invoke a registered
|
|
10300
|
+
* call — invoke a registered function
|
|
9662
10301
|
* exec — execute arbitrary JS (requires allowExec)
|
|
9663
10302
|
*
|
|
9664
10303
|
* Target resolution:
|
|
@@ -9667,9 +10306,9 @@
|
|
|
9667
10306
|
*
|
|
9668
10307
|
* @param {Object} msg - Protocol message
|
|
9669
10308
|
* @returns {boolean} true if the message was applied successfully
|
|
9670
|
-
* @category
|
|
10309
|
+
* @category Core
|
|
9671
10310
|
*/
|
|
9672
|
-
bw.
|
|
10311
|
+
bw.apply = function(msg) {
|
|
9673
10312
|
if (!msg || !msg.type) return false;
|
|
9674
10313
|
|
|
9675
10314
|
var type = msg.type;
|
|
@@ -9695,15 +10334,15 @@
|
|
|
9695
10334
|
} else if (type === 'remove') {
|
|
9696
10335
|
var toRemove = bw._el(target);
|
|
9697
10336
|
if (!toRemove) return false;
|
|
9698
|
-
if (
|
|
10337
|
+
if (_is(bw.cleanup, 'function')) bw.cleanup(toRemove);
|
|
9699
10338
|
toRemove.remove();
|
|
9700
10339
|
return true;
|
|
9701
10340
|
|
|
9702
10341
|
} else if (type === 'batch') {
|
|
9703
|
-
if (!
|
|
10342
|
+
if (!_isA(msg.ops)) return false;
|
|
9704
10343
|
var allOk = true;
|
|
9705
10344
|
msg.ops.forEach(function(op) {
|
|
9706
|
-
if (!bw.
|
|
10345
|
+
if (!bw.apply(op)) allOk = false;
|
|
9707
10346
|
});
|
|
9708
10347
|
return allOk;
|
|
9709
10348
|
|
|
@@ -9716,26 +10355,26 @@
|
|
|
9716
10355
|
bw._clientFunctions[msg.name] = new Function('return ' + msg.body)();
|
|
9717
10356
|
return true;
|
|
9718
10357
|
} catch (e) {
|
|
9719
|
-
|
|
10358
|
+
_ce('[bw] register error:', msg.name, e);
|
|
9720
10359
|
return false;
|
|
9721
10360
|
}
|
|
9722
10361
|
|
|
9723
10362
|
} else if (type === 'call') {
|
|
9724
10363
|
if (!msg.name) return false;
|
|
9725
|
-
var fn = bw._clientFunctions[msg.name]
|
|
9726
|
-
if (
|
|
10364
|
+
var fn = bw._clientFunctions[msg.name];
|
|
10365
|
+
if (!_is(fn, 'function')) return false;
|
|
9727
10366
|
try {
|
|
9728
|
-
var args =
|
|
10367
|
+
var args = _isA(msg.args) ? msg.args : [];
|
|
9729
10368
|
fn.apply(null, args);
|
|
9730
10369
|
return true;
|
|
9731
10370
|
} catch (e) {
|
|
9732
|
-
|
|
10371
|
+
_ce('[bw] call error:', msg.name, e);
|
|
9733
10372
|
return false;
|
|
9734
10373
|
}
|
|
9735
10374
|
|
|
9736
10375
|
} else if (type === 'exec') {
|
|
9737
10376
|
if (!bw._allowExec) {
|
|
9738
|
-
|
|
10377
|
+
_cw('[bw] exec rejected: allowExec is not enabled');
|
|
9739
10378
|
return false;
|
|
9740
10379
|
}
|
|
9741
10380
|
if (!msg.code) return false;
|
|
@@ -9743,7 +10382,7 @@
|
|
|
9743
10382
|
new Function(msg.code)();
|
|
9744
10383
|
return true;
|
|
9745
10384
|
} catch (e) {
|
|
9746
|
-
|
|
10385
|
+
_ce('[bw] exec error:', e);
|
|
9747
10386
|
return false;
|
|
9748
10387
|
}
|
|
9749
10388
|
}
|
|
@@ -9751,139 +10390,6 @@
|
|
|
9751
10390
|
return false;
|
|
9752
10391
|
};
|
|
9753
10392
|
|
|
9754
|
-
/**
|
|
9755
|
-
* Connect to a bwserve SSE endpoint and apply protocol messages automatically.
|
|
9756
|
-
*
|
|
9757
|
-
* Returns a connection object with sendAction(), on(), and close() methods.
|
|
9758
|
-
*
|
|
9759
|
-
* @param {string} url - SSE endpoint URL (e.g., '/__bw/events/client-1')
|
|
9760
|
-
* @param {Object} [opts] - Connection options
|
|
9761
|
-
* @param {string} [opts.transport='sse'] - Transport type: 'sse' (default) or 'poll'
|
|
9762
|
-
* @param {number} [opts.interval=2000] - Poll interval in ms (only for 'poll' transport)
|
|
9763
|
-
* @param {string} [opts.actionUrl] - POST endpoint for actions (default: derived from url)
|
|
9764
|
-
* @param {boolean} [opts.reconnect=true] - Auto-reconnect on disconnect
|
|
9765
|
-
* @param {boolean} [opts.allowExec=false] - Enable exec message type (arbitrary JS execution)
|
|
9766
|
-
* @param {Function} [opts.onStatus] - Status callback: 'connecting'|'connected'|'disconnected'
|
|
9767
|
-
* @param {Function} [opts.onMessage] - Raw message callback (before clientApply)
|
|
9768
|
-
* @returns {Object} Connection object { sendAction, on, close, status }
|
|
9769
|
-
* @category Server
|
|
9770
|
-
*/
|
|
9771
|
-
bw.clientConnect = function(url, opts) {
|
|
9772
|
-
opts = opts || {};
|
|
9773
|
-
var transport = opts.transport || 'sse';
|
|
9774
|
-
var actionUrl = opts.actionUrl || url.replace(/\/events\//, '/action/');
|
|
9775
|
-
var reconnect = opts.reconnect !== false;
|
|
9776
|
-
var onStatus = opts.onStatus || function() {};
|
|
9777
|
-
var onMessage = opts.onMessage || null;
|
|
9778
|
-
var handlers = {};
|
|
9779
|
-
// Set the global allowExec flag from connection options
|
|
9780
|
-
bw._allowExec = !!opts.allowExec;
|
|
9781
|
-
var conn = {
|
|
9782
|
-
status: 'connecting',
|
|
9783
|
-
_es: null,
|
|
9784
|
-
_pollTimer: null
|
|
9785
|
-
};
|
|
9786
|
-
|
|
9787
|
-
function setStatus(s) {
|
|
9788
|
-
conn.status = s;
|
|
9789
|
-
onStatus(s);
|
|
9790
|
-
}
|
|
9791
|
-
|
|
9792
|
-
function handleMessage(data) {
|
|
9793
|
-
try {
|
|
9794
|
-
var msg = typeof data === 'string' ? bw.clientParse(data) : data;
|
|
9795
|
-
if (onMessage) onMessage(msg);
|
|
9796
|
-
if (handlers.message) handlers.message(msg);
|
|
9797
|
-
bw.clientApply(msg);
|
|
9798
|
-
} catch (e) {
|
|
9799
|
-
if (handlers.error) handlers.error(e);
|
|
9800
|
-
}
|
|
9801
|
-
}
|
|
9802
|
-
|
|
9803
|
-
if (transport === 'sse' && typeof EventSource !== 'undefined') {
|
|
9804
|
-
setStatus('connecting');
|
|
9805
|
-
var es = new EventSource(url);
|
|
9806
|
-
conn._es = es;
|
|
9807
|
-
|
|
9808
|
-
es.onopen = function() {
|
|
9809
|
-
setStatus('connected');
|
|
9810
|
-
if (handlers.open) handlers.open();
|
|
9811
|
-
};
|
|
9812
|
-
|
|
9813
|
-
es.onmessage = function(e) {
|
|
9814
|
-
handleMessage(e.data);
|
|
9815
|
-
};
|
|
9816
|
-
|
|
9817
|
-
es.onerror = function() {
|
|
9818
|
-
if (conn.status === 'connected') {
|
|
9819
|
-
setStatus('disconnected');
|
|
9820
|
-
}
|
|
9821
|
-
if (handlers.error) handlers.error(new Error('SSE connection error'));
|
|
9822
|
-
if (!reconnect) {
|
|
9823
|
-
es.close();
|
|
9824
|
-
}
|
|
9825
|
-
// EventSource auto-reconnects by default when reconnect=true
|
|
9826
|
-
};
|
|
9827
|
-
} else if (transport === 'poll') {
|
|
9828
|
-
var interval = opts.interval || 2000;
|
|
9829
|
-
setStatus('connected');
|
|
9830
|
-
conn._pollTimer = setInterval(function() {
|
|
9831
|
-
fetch(url).then(function(r) { return r.json(); }).then(function(msgs) {
|
|
9832
|
-
if (Array.isArray(msgs)) {
|
|
9833
|
-
msgs.forEach(handleMessage);
|
|
9834
|
-
} else if (msgs && msgs.type) {
|
|
9835
|
-
handleMessage(msgs);
|
|
9836
|
-
}
|
|
9837
|
-
}).catch(function(e) {
|
|
9838
|
-
if (handlers.error) handlers.error(e);
|
|
9839
|
-
});
|
|
9840
|
-
}, interval);
|
|
9841
|
-
}
|
|
9842
|
-
|
|
9843
|
-
/**
|
|
9844
|
-
* Send an action to the server via POST.
|
|
9845
|
-
* @param {string} action - Action name
|
|
9846
|
-
* @param {Object} [data] - Action payload
|
|
9847
|
-
*/
|
|
9848
|
-
conn.sendAction = function(action, data) {
|
|
9849
|
-
var body = JSON.stringify({ type: 'action', action: action, data: data || {} });
|
|
9850
|
-
fetch(actionUrl, {
|
|
9851
|
-
method: 'POST',
|
|
9852
|
-
headers: { 'Content-Type': 'application/json' },
|
|
9853
|
-
body: body
|
|
9854
|
-
}).catch(function(e) {
|
|
9855
|
-
if (handlers.error) handlers.error(e);
|
|
9856
|
-
});
|
|
9857
|
-
};
|
|
9858
|
-
|
|
9859
|
-
/**
|
|
9860
|
-
* Register an event handler.
|
|
9861
|
-
* @param {string} event - 'open'|'message'|'error'|'close'
|
|
9862
|
-
* @param {Function} handler
|
|
9863
|
-
*/
|
|
9864
|
-
conn.on = function(event, handler) {
|
|
9865
|
-
handlers[event] = handler;
|
|
9866
|
-
return conn;
|
|
9867
|
-
};
|
|
9868
|
-
|
|
9869
|
-
/**
|
|
9870
|
-
* Close the connection.
|
|
9871
|
-
*/
|
|
9872
|
-
conn.close = function() {
|
|
9873
|
-
if (conn._es) {
|
|
9874
|
-
conn._es.close();
|
|
9875
|
-
conn._es = null;
|
|
9876
|
-
}
|
|
9877
|
-
if (conn._pollTimer) {
|
|
9878
|
-
clearInterval(conn._pollTimer);
|
|
9879
|
-
conn._pollTimer = null;
|
|
9880
|
-
}
|
|
9881
|
-
setStatus('disconnected');
|
|
9882
|
-
if (handlers.close) handlers.close();
|
|
9883
|
-
};
|
|
9884
|
-
|
|
9885
|
-
return conn;
|
|
9886
|
-
};
|
|
9887
10393
|
|
|
9888
10394
|
// ===================================================================================
|
|
9889
10395
|
// bw.inspect() — Debug utility
|
|
@@ -9911,33 +10417,33 @@
|
|
|
9911
10417
|
el = target.element;
|
|
9912
10418
|
comp = target;
|
|
9913
10419
|
} else {
|
|
9914
|
-
if (
|
|
10420
|
+
if (_is(target, 'string')) {
|
|
9915
10421
|
el = bw.$(target)[0];
|
|
9916
10422
|
}
|
|
9917
10423
|
if (!el) {
|
|
9918
|
-
|
|
10424
|
+
_cw('bw.inspect: element not found');
|
|
9919
10425
|
return null;
|
|
9920
10426
|
}
|
|
9921
10427
|
comp = el._bwComponentHandle;
|
|
9922
10428
|
}
|
|
9923
10429
|
if (!comp) {
|
|
9924
|
-
|
|
9925
|
-
|
|
9926
|
-
|
|
9927
|
-
|
|
10430
|
+
_cl('bw.inspect: no ComponentHandle on this element');
|
|
10431
|
+
_cl(' Tag:', el.tagName);
|
|
10432
|
+
_cl(' Classes:', el.className);
|
|
10433
|
+
_cl(' _bw_state:', el._bw_state || '(none)');
|
|
9928
10434
|
return null;
|
|
9929
10435
|
}
|
|
9930
10436
|
var deps = comp._bindings.reduce(function(s, b) {
|
|
9931
10437
|
return s.concat(b.deps || []);
|
|
9932
10438
|
}, []).filter(function(v, i, a) { return a.indexOf(v) === i; });
|
|
9933
10439
|
console.group('Component: ' + comp._bwId);
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
|
|
9937
|
-
|
|
9938
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
10440
|
+
_cl('State:', comp._state);
|
|
10441
|
+
_cl('Bindings:', comp._bindings.length, '(deps:', deps, ')');
|
|
10442
|
+
_cl('Methods:', _keys(comp._methods));
|
|
10443
|
+
_cl('Actions:', _keys(comp._actions));
|
|
10444
|
+
_cl('User tag:', comp._userTag || '(none)');
|
|
10445
|
+
_cl('Mounted:', comp.mounted);
|
|
10446
|
+
_cl('Element:', comp.element);
|
|
9941
10447
|
console.groupEnd();
|
|
9942
10448
|
return comp;
|
|
9943
10449
|
};
|
|
@@ -9960,8 +10466,8 @@
|
|
|
9960
10466
|
// Pre-extract all binding expressions
|
|
9961
10467
|
var precompiled = [];
|
|
9962
10468
|
function walkExpressions(node) {
|
|
9963
|
-
if (!node
|
|
9964
|
-
if (
|
|
10469
|
+
if (!_is(node, 'object')) return;
|
|
10470
|
+
if (_is(node.c, 'string') && node.c.indexOf('${') >= 0) {
|
|
9965
10471
|
var parsed = bw._parseBindings(node.c);
|
|
9966
10472
|
for (var i = 0; i < parsed.length; i++) {
|
|
9967
10473
|
try {
|
|
@@ -9976,9 +10482,9 @@
|
|
|
9976
10482
|
}
|
|
9977
10483
|
if (node.a) {
|
|
9978
10484
|
for (var key in node.a) {
|
|
9979
|
-
if (
|
|
10485
|
+
if (_hop.call(node.a, key)) {
|
|
9980
10486
|
var v = node.a[key];
|
|
9981
|
-
if (
|
|
10487
|
+
if (_is(v, 'string') && v.indexOf('${') >= 0) {
|
|
9982
10488
|
var parsed2 = bw._parseBindings(v);
|
|
9983
10489
|
for (var j = 0; j < parsed2.length; j++) {
|
|
9984
10490
|
try {
|
|
@@ -9994,9 +10500,9 @@
|
|
|
9994
10500
|
}
|
|
9995
10501
|
}
|
|
9996
10502
|
}
|
|
9997
|
-
if (
|
|
10503
|
+
if (_isA(node.c)) {
|
|
9998
10504
|
for (var k = 0; k < node.c.length; k++) walkExpressions(node.c[k]);
|
|
9999
|
-
} else if (node.c
|
|
10505
|
+
} else if (_is(node.c, 'object') && node.c.t) {
|
|
10000
10506
|
walkExpressions(node.c);
|
|
10001
10507
|
}
|
|
10002
10508
|
}
|
|
@@ -10008,7 +10514,7 @@
|
|
|
10008
10514
|
handle._precompiledBindings = precompiled;
|
|
10009
10515
|
if (initialState) {
|
|
10010
10516
|
for (var k in initialState) {
|
|
10011
|
-
if (
|
|
10517
|
+
if (_hop.call(initialState, k)) {
|
|
10012
10518
|
handle._state[k] = initialState[k];
|
|
10013
10519
|
}
|
|
10014
10520
|
}
|
|
@@ -10039,18 +10545,18 @@
|
|
|
10039
10545
|
bw.css = function(rules, options = {}) {
|
|
10040
10546
|
const { minify = false, pretty = !minify } = options;
|
|
10041
10547
|
|
|
10042
|
-
if (
|
|
10548
|
+
if (_is(rules, 'string')) return rules;
|
|
10043
10549
|
|
|
10044
10550
|
let css = '';
|
|
10045
10551
|
const indent = pretty ? ' ' : '';
|
|
10046
10552
|
const newline = pretty ? '\n' : '';
|
|
10047
10553
|
const space = pretty ? ' ' : '';
|
|
10048
10554
|
|
|
10049
|
-
if (
|
|
10555
|
+
if (_isA(rules)) {
|
|
10050
10556
|
css = rules.map(rule => bw.css(rule, options)).join(newline);
|
|
10051
|
-
} else if (
|
|
10557
|
+
} else if (_is(rules, 'object')) {
|
|
10052
10558
|
Object.entries(rules).forEach(([selector, styles]) => {
|
|
10053
|
-
if (
|
|
10559
|
+
if (_is(styles, 'object')) {
|
|
10054
10560
|
// Handle @media, @keyframes, @supports — recurse into nested block
|
|
10055
10561
|
if (selector.charAt(0) === '@') {
|
|
10056
10562
|
const inner = bw.css(styles, options);
|
|
@@ -10092,14 +10598,14 @@
|
|
|
10092
10598
|
* @returns {Element} The style element
|
|
10093
10599
|
* @category CSS & Styling
|
|
10094
10600
|
* @see bw.css
|
|
10095
|
-
* @see bw.
|
|
10601
|
+
* @see bw.loadStyles
|
|
10096
10602
|
* @example
|
|
10097
10603
|
* bw.injectCSS('.my-class { color: red; }');
|
|
10098
10604
|
* bw.injectCSS({ '.card': { padding: '1rem' } }, { id: 'card-styles' });
|
|
10099
10605
|
*/
|
|
10100
10606
|
bw.injectCSS = function(css, options = {}) {
|
|
10101
10607
|
if (!bw._isBrowser) {
|
|
10102
|
-
|
|
10608
|
+
_cw('bw.injectCSS requires a DOM environment');
|
|
10103
10609
|
return null;
|
|
10104
10610
|
}
|
|
10105
10611
|
|
|
@@ -10116,7 +10622,7 @@
|
|
|
10116
10622
|
}
|
|
10117
10623
|
|
|
10118
10624
|
// Convert CSS if needed
|
|
10119
|
-
const cssStr =
|
|
10625
|
+
const cssStr = _is(css, 'string') ? css : bw.css(css, options);
|
|
10120
10626
|
|
|
10121
10627
|
// Set or append CSS
|
|
10122
10628
|
if (append && styleEl.textContent) {
|
|
@@ -10137,113 +10643,19 @@
|
|
|
10137
10643
|
* @param {...Object} styles - Style objects to merge (left-to-right)
|
|
10138
10644
|
* @returns {Object} Merged style object
|
|
10139
10645
|
* @category CSS & Styling
|
|
10140
|
-
* @see bw.u
|
|
10141
10646
|
* @example
|
|
10142
|
-
* var style = bw.s(
|
|
10647
|
+
* var style = bw.s({ display: 'flex' }, { gap: '1rem' }, { color: 'red' });
|
|
10143
10648
|
* // => { display: 'flex', gap: '1rem', color: 'red' }
|
|
10144
10649
|
*/
|
|
10145
10650
|
bw.s = function() {
|
|
10146
10651
|
var result = {};
|
|
10147
10652
|
for (var i = 0; i < arguments.length; i++) {
|
|
10148
10653
|
var arg = arguments[i];
|
|
10149
|
-
if (arg
|
|
10654
|
+
if (_is(arg, 'object')) Object.assign(result, arg);
|
|
10150
10655
|
}
|
|
10151
10656
|
return result;
|
|
10152
10657
|
};
|
|
10153
10658
|
|
|
10154
|
-
/**
|
|
10155
|
-
* Pre-built CSS utility objects (like Tailwind utilities, but in JS).
|
|
10156
|
-
*
|
|
10157
|
-
* Compose with `bw.s()` to build inline styles without writing raw CSS strings.
|
|
10158
|
-
* Includes flex, padding, margin, typography, color, border, and transition utilities.
|
|
10159
|
-
*
|
|
10160
|
-
* @category CSS & Styling
|
|
10161
|
-
* @see bw.s
|
|
10162
|
-
* @example
|
|
10163
|
-
* { t: 'div', a: { style: bw.s(bw.u.flex, bw.u.gap4, bw.u.p4) },
|
|
10164
|
-
* c: 'Flexbox with 1rem gap and padding' }
|
|
10165
|
-
*/
|
|
10166
|
-
bw.u = {
|
|
10167
|
-
// Display
|
|
10168
|
-
flex: { display: 'flex' },
|
|
10169
|
-
flexCol: { display: 'flex', flexDirection: 'column' },
|
|
10170
|
-
flexRow: { display: 'flex', flexDirection: 'row' },
|
|
10171
|
-
flexWrap: { display: 'flex', flexWrap: 'wrap' },
|
|
10172
|
-
block: { display: 'block' },
|
|
10173
|
-
inline: { display: 'inline' },
|
|
10174
|
-
hidden: { display: 'none' },
|
|
10175
|
-
|
|
10176
|
-
// Flex alignment
|
|
10177
|
-
justifyCenter: { justifyContent: 'center' },
|
|
10178
|
-
justifyBetween: { justifyContent: 'space-between' },
|
|
10179
|
-
justifyEnd: { justifyContent: 'flex-end' },
|
|
10180
|
-
alignCenter: { alignItems: 'center' },
|
|
10181
|
-
alignStart: { alignItems: 'flex-start' },
|
|
10182
|
-
alignEnd: { alignItems: 'flex-end' },
|
|
10183
|
-
|
|
10184
|
-
// Gap (0.25rem increments)
|
|
10185
|
-
gap1: { gap: '0.25rem' },
|
|
10186
|
-
gap2: { gap: '0.5rem' },
|
|
10187
|
-
gap3: { gap: '0.75rem' },
|
|
10188
|
-
gap4: { gap: '1rem' },
|
|
10189
|
-
gap6: { gap: '1.5rem' },
|
|
10190
|
-
gap8: { gap: '2rem' },
|
|
10191
|
-
|
|
10192
|
-
// Padding
|
|
10193
|
-
p0: { padding: '0' },
|
|
10194
|
-
p1: { padding: '0.25rem' },
|
|
10195
|
-
p2: { padding: '0.5rem' },
|
|
10196
|
-
p3: { padding: '0.75rem' },
|
|
10197
|
-
p4: { padding: '1rem' },
|
|
10198
|
-
p6: { padding: '1.5rem' },
|
|
10199
|
-
p8: { padding: '2rem' },
|
|
10200
|
-
px4: { paddingLeft: '1rem', paddingRight: '1rem' },
|
|
10201
|
-
py2: { paddingTop: '0.5rem', paddingBottom: '0.5rem' },
|
|
10202
|
-
py4: { paddingTop: '1rem', paddingBottom: '1rem' },
|
|
10203
|
-
|
|
10204
|
-
// Margin (same scale)
|
|
10205
|
-
m0: { margin: '0' },
|
|
10206
|
-
m4: { margin: '1rem' },
|
|
10207
|
-
mt2: { marginTop: '0.5rem' },
|
|
10208
|
-
mt4: { marginTop: '1rem' },
|
|
10209
|
-
mb2: { marginBottom: '0.5rem' },
|
|
10210
|
-
mb4: { marginBottom: '1rem' },
|
|
10211
|
-
mx_auto: { marginLeft: 'auto', marginRight: 'auto' },
|
|
10212
|
-
|
|
10213
|
-
// Typography
|
|
10214
|
-
textSm: { fontSize: '0.875rem' },
|
|
10215
|
-
textBase: { fontSize: '1rem' },
|
|
10216
|
-
textLg: { fontSize: '1.125rem' },
|
|
10217
|
-
textXl: { fontSize: '1.25rem' },
|
|
10218
|
-
text2xl: { fontSize: '1.5rem' },
|
|
10219
|
-
text3xl: { fontSize: '1.875rem' },
|
|
10220
|
-
bold: { fontWeight: '700' },
|
|
10221
|
-
semibold: { fontWeight: '600' },
|
|
10222
|
-
italic: { fontStyle: 'italic' },
|
|
10223
|
-
textCenter: { textAlign: 'center' },
|
|
10224
|
-
textRight: { textAlign: 'right' },
|
|
10225
|
-
|
|
10226
|
-
// Colors (from design tokens)
|
|
10227
|
-
bgWhite: { background: '#ffffff' },
|
|
10228
|
-
bgTeal: { background: '#006666', color: '#ffffff' },
|
|
10229
|
-
textWhite: { color: '#ffffff' },
|
|
10230
|
-
textTeal: { color: '#006666' },
|
|
10231
|
-
textMuted: { color: '#888' },
|
|
10232
|
-
|
|
10233
|
-
// Borders
|
|
10234
|
-
rounded: { borderRadius: '0.375rem' },
|
|
10235
|
-
roundedLg: { borderRadius: '0.5rem' },
|
|
10236
|
-
roundedFull: { borderRadius: '9999px' },
|
|
10237
|
-
border: { border: '1px solid #d8d8d8' },
|
|
10238
|
-
|
|
10239
|
-
// Sizing
|
|
10240
|
-
wFull: { width: '100%' },
|
|
10241
|
-
hFull: { height: '100%' },
|
|
10242
|
-
|
|
10243
|
-
// Transitions
|
|
10244
|
-
transition: { transition: 'all 0.2s ease' }
|
|
10245
|
-
};
|
|
10246
|
-
|
|
10247
10659
|
/**
|
|
10248
10660
|
* Generate responsive CSS with media query breakpoints.
|
|
10249
10661
|
*
|
|
@@ -10269,7 +10681,7 @@
|
|
|
10269
10681
|
bw.responsive = function(selector, breakpoints) {
|
|
10270
10682
|
var sizes = { sm: '576px', md: '768px', lg: '992px', xl: '1200px' };
|
|
10271
10683
|
var parts = [];
|
|
10272
|
-
|
|
10684
|
+
_keys(breakpoints).forEach(function(key) {
|
|
10273
10685
|
var rules = {};
|
|
10274
10686
|
if (key === 'base') {
|
|
10275
10687
|
rules[selector] = breakpoints[key];
|
|
@@ -10341,18 +10753,18 @@
|
|
|
10341
10753
|
if (!selector) return [];
|
|
10342
10754
|
|
|
10343
10755
|
// Already an array
|
|
10344
|
-
if (
|
|
10756
|
+
if (_isA(selector)) return selector;
|
|
10345
10757
|
|
|
10346
10758
|
// Single element
|
|
10347
10759
|
if (selector.nodeType) return [selector];
|
|
10348
10760
|
|
|
10349
10761
|
// NodeList or HTMLCollection
|
|
10350
|
-
if (selector.length !== undefined &&
|
|
10762
|
+
if (selector.length !== undefined && !_is(selector, 'string')) {
|
|
10351
10763
|
return Array.from(selector);
|
|
10352
10764
|
}
|
|
10353
10765
|
|
|
10354
10766
|
// CSS selector string
|
|
10355
|
-
if (
|
|
10767
|
+
if (_is(selector, 'string')) {
|
|
10356
10768
|
return Array.from(document.querySelectorAll(selector));
|
|
10357
10769
|
}
|
|
10358
10770
|
|
|
@@ -10365,103 +10777,49 @@
|
|
|
10365
10777
|
};
|
|
10366
10778
|
}
|
|
10367
10779
|
|
|
10368
|
-
/**
|
|
10369
|
-
* Load the built-in Bootstrap-inspired default stylesheet.
|
|
10370
|
-
*
|
|
10371
|
-
* Injects bitwrench's batteries-included CSS (buttons, cards, grids, forms,
|
|
10372
|
-
* alerts, badges, nav, tabs, etc.) into the document head. Call once at app startup.
|
|
10373
|
-
* Returns null in Node.js (no DOM).
|
|
10374
|
-
*
|
|
10375
|
-
* @param {Object} [options] - Style loading options
|
|
10376
|
-
* @param {boolean} [options.minify=true] - Minify the CSS output
|
|
10377
|
-
* @returns {Element|null} Style element if in browser, null in Node.js
|
|
10378
|
-
* @category CSS & Styling
|
|
10379
|
-
* @see bw.setTheme
|
|
10380
|
-
* @see bw.applyTheme
|
|
10381
|
-
* @see bw.toggleTheme
|
|
10382
|
-
* @example
|
|
10383
|
-
* bw.loadDefaultStyles(); // inject all default CSS
|
|
10384
|
-
*/
|
|
10385
|
-
bw.loadDefaultStyles = function(options = {}) {
|
|
10386
|
-
const { minify = true, palette } = options;
|
|
10387
|
-
|
|
10388
|
-
// 1. Inject structural CSS (layout, sizing — never changes with theme)
|
|
10389
|
-
if (bw._isBrowser) {
|
|
10390
|
-
var structuralCSS = bw.css(getStructuralStyles());
|
|
10391
|
-
bw.injectCSS(structuralCSS, { id: 'bw_structural', append: false, minify: minify });
|
|
10392
|
-
}
|
|
10393
10780
|
|
|
10394
|
-
|
|
10395
|
-
|
|
10396
|
-
|
|
10397
|
-
return result;
|
|
10398
|
-
};
|
|
10781
|
+
// =========================================================================
|
|
10782
|
+
// v2.0.18 Clean Styles API — makeStyles / applyStyles / loadStyles / etc.
|
|
10783
|
+
// =========================================================================
|
|
10399
10784
|
|
|
10785
|
+
/**
|
|
10786
|
+
* Convert a scope selector to a <style> element id.
|
|
10787
|
+
* @private
|
|
10788
|
+
* @param {string} [scope] - Scope selector (e.g. '#my-dashboard', '.preview')
|
|
10789
|
+
* @returns {string} Style element id (e.g. 'bw_style_my_dashboard')
|
|
10790
|
+
*/
|
|
10791
|
+
function _scopeToStyleId(scope) {
|
|
10792
|
+
if (!scope || scope === '' || scope === 'global') return 'bw_style_global';
|
|
10793
|
+
if (scope === 'reset') return 'bw_style_reset';
|
|
10794
|
+
// Strip leading # or . and convert - to _
|
|
10795
|
+
var clean = scope.replace(/^[#.]/, '').replace(/-/g, '_');
|
|
10796
|
+
return 'bw_style_' + clean;
|
|
10797
|
+
}
|
|
10400
10798
|
|
|
10401
10799
|
/**
|
|
10402
|
-
* Generate a complete
|
|
10800
|
+
* Generate a complete styles object from seed colors and layout config.
|
|
10801
|
+
* Pure function — no DOM, no state, no side effects.
|
|
10403
10802
|
*
|
|
10404
|
-
*
|
|
10405
|
-
* forms, nav, tables, tabs, list groups, pagination, progress, hero, utilities)
|
|
10406
|
-
* scoped under `.name` class. Multiple themes can coexist in the stylesheet.
|
|
10407
|
-
* Swap themes by changing the class on a container element.
|
|
10803
|
+
* All parameters are optional. Defaults to the bitwrench default palette.
|
|
10408
10804
|
*
|
|
10409
|
-
* @param {
|
|
10410
|
-
* @param {
|
|
10411
|
-
* @param {string} config.
|
|
10412
|
-
* @param {string} config.
|
|
10413
|
-
* @param {string} [config.tertiary] - Tertiary/accent color hex (defaults to primary)
|
|
10414
|
-
* @param {string} [config.success='#198754'] - Success color hex
|
|
10415
|
-
* @param {string} [config.danger='#dc3545'] - Danger color hex
|
|
10416
|
-
* @param {string} [config.warning='#ffc107'] - Warning color hex
|
|
10417
|
-
* @param {string} [config.info='#0dcaf0'] - Info color hex
|
|
10418
|
-
* @param {string} [config.light='#f8f9fa'] - Light color hex
|
|
10419
|
-
* @param {string} [config.dark='#212529'] - Dark color hex
|
|
10420
|
-
* @param {string} [config.background] - Page background hex (default: '#ffffff' light, derived dark)
|
|
10421
|
-
* @param {string} [config.surface] - Surface/card background hex (default: '#f8f9fa' light, derived dark)
|
|
10805
|
+
* @param {Object} [config] - Style configuration
|
|
10806
|
+
* @param {string} [config.primary='#006666'] - Primary brand color hex
|
|
10807
|
+
* @param {string} [config.secondary='#6c757d'] - Secondary color hex
|
|
10808
|
+
* @param {string} [config.tertiary] - Tertiary color hex (defaults to primary)
|
|
10422
10809
|
* @param {string} [config.spacing='normal'] - 'compact' | 'normal' | 'spacious'
|
|
10423
10810
|
* @param {string} [config.radius='md'] - 'none' | 'sm' | 'md' | 'lg' | 'pill'
|
|
10424
|
-
* @
|
|
10425
|
-
* @param {string|number} [config.typeRatio='normal'] - 'tight' | 'normal' | 'relaxed' | 'dramatic' or a number
|
|
10426
|
-
* @param {string} [config.elevation='md'] - 'flat' | 'sm' | 'md' | 'lg'
|
|
10427
|
-
* @param {string} [config.motion='standard'] - 'reduced' | 'standard' | 'expressive'
|
|
10428
|
-
* @param {number} [config.harmonize=0.20] - 0-1, semantic color hue shift toward primary
|
|
10429
|
-
* @param {boolean} [config.inject=true] - Inject into DOM (browser only)
|
|
10430
|
-
* @returns {Object} { css, palette, name, isLightPrimary, alternate: { css, palette } }
|
|
10811
|
+
* @returns {Object} { css, alternateCss, rules, alternateRules, palette, alternatePalette, isLightPrimary }
|
|
10431
10812
|
* @category CSS & Styling
|
|
10432
|
-
* @see bw.
|
|
10433
|
-
* @see bw.
|
|
10434
|
-
* @see bw.loadDefaultStyles
|
|
10813
|
+
* @see bw.applyStyles
|
|
10814
|
+
* @see bw.loadStyles
|
|
10435
10815
|
* @example
|
|
10436
|
-
*
|
|
10437
|
-
*
|
|
10438
|
-
*
|
|
10439
|
-
* secondary: '#90e0ef',
|
|
10440
|
-
* tertiary: '#00b4d8'
|
|
10441
|
-
* });
|
|
10442
|
-
*
|
|
10443
|
-
* // Apply to a container
|
|
10444
|
-
* document.getElementById('app').classList.add('ocean');
|
|
10445
|
-
*
|
|
10446
|
-
* // Toggle to alternate palette
|
|
10447
|
-
* bw.toggleTheme();
|
|
10448
|
-
*
|
|
10449
|
-
* // Generate CSS for static export (Node.js)
|
|
10450
|
-
* var result = bw.generateTheme('sunset', {
|
|
10451
|
-
* primary: '#e76f51',
|
|
10452
|
-
* secondary: '#264653',
|
|
10453
|
-
* inject: false
|
|
10454
|
-
* });
|
|
10455
|
-
* fs.writeFileSync('sunset.css', result.css + result.alternate.css);
|
|
10816
|
+
* var styles = bw.makeStyles({ primary: '#4f46e5', secondary: '#d97706' });
|
|
10817
|
+
* console.log(styles.palette.primary.base); // '#4f46e5'
|
|
10818
|
+
* // styles.css contains all themed CSS — nothing injected
|
|
10456
10819
|
*/
|
|
10457
|
-
bw.
|
|
10458
|
-
|
|
10459
|
-
|
|
10460
|
-
}
|
|
10461
|
-
|
|
10462
|
-
// Merge with defaults; if user didn't supply tertiary, default to their primary
|
|
10463
|
-
var fullConfig = Object.assign({}, DEFAULT_PALETTE_CONFIG, config);
|
|
10464
|
-
if (!config.tertiary) fullConfig.tertiary = fullConfig.primary;
|
|
10820
|
+
bw.makeStyles = function(config) {
|
|
10821
|
+
var fullConfig = Object.assign({}, DEFAULT_PALETTE_CONFIG, config || {});
|
|
10822
|
+
if (config && !config.tertiary) fullConfig.tertiary = fullConfig.primary;
|
|
10465
10823
|
|
|
10466
10824
|
// Derive primary palette
|
|
10467
10825
|
var palette = derivePalette(fullConfig);
|
|
@@ -10469,131 +10827,207 @@
|
|
|
10469
10827
|
// Resolve layout
|
|
10470
10828
|
var layout = resolveLayout(fullConfig);
|
|
10471
10829
|
|
|
10472
|
-
// Generate primary themed CSS rules
|
|
10473
|
-
var themedRules = generateThemedCSS(
|
|
10830
|
+
// Generate primary themed CSS rules (unscoped)
|
|
10831
|
+
var themedRules = generateThemedCSS('', palette, layout);
|
|
10474
10832
|
var cssStr = bw.css(themedRules);
|
|
10475
10833
|
|
|
10476
10834
|
// Derive alternate palette (luminance-inverted)
|
|
10477
10835
|
var altConfig = deriveAlternateConfig(fullConfig);
|
|
10478
10836
|
var altPalette = derivePalette(altConfig);
|
|
10479
10837
|
|
|
10480
|
-
// Generate alternate CSS
|
|
10481
|
-
|
|
10482
|
-
var
|
|
10838
|
+
// Generate alternate CSS rules WITHOUT .bw_theme_alt prefix (raw rules)
|
|
10839
|
+
// applyStyles() wraps them appropriately based on scope
|
|
10840
|
+
var altRawRules = generateThemedCSS('', altPalette, layout);
|
|
10841
|
+
|
|
10842
|
+
// Add body-level surface overrides for the alternate palette.
|
|
10843
|
+
// When .bw_theme_alt is on <html>, ".bw_theme_alt body" correctly matches.
|
|
10844
|
+
altRawRules['body'] = {
|
|
10845
|
+
'color': altPalette.dark.base,
|
|
10846
|
+
'background-color': altPalette.surface || altPalette.light.base
|
|
10847
|
+
};
|
|
10848
|
+
|
|
10849
|
+
var altCssStr = bw.css(altRawRules);
|
|
10483
10850
|
|
|
10484
10851
|
// Determine if primary is light-flavored
|
|
10485
10852
|
var lightPrimary = isLightPalette(fullConfig);
|
|
10486
10853
|
|
|
10487
|
-
|
|
10488
|
-
|
|
10489
|
-
|
|
10490
|
-
|
|
10491
|
-
|
|
10492
|
-
|
|
10493
|
-
|
|
10494
|
-
|
|
10495
|
-
|
|
10854
|
+
return {
|
|
10855
|
+
css: cssStr,
|
|
10856
|
+
alternateCss: altCssStr,
|
|
10857
|
+
rules: themedRules,
|
|
10858
|
+
alternateRules: altRawRules,
|
|
10859
|
+
palette: palette,
|
|
10860
|
+
alternatePalette: altPalette,
|
|
10861
|
+
isLightPrimary: lightPrimary
|
|
10862
|
+
};
|
|
10863
|
+
};
|
|
10496
10864
|
|
|
10497
|
-
|
|
10865
|
+
/**
|
|
10866
|
+
* Inject styles into the DOM with optional scoping.
|
|
10867
|
+
*
|
|
10868
|
+
* Takes a styles object from `makeStyles()` and creates a single `<style>`
|
|
10869
|
+
* element in `<head>`. If a scope selector is provided, all CSS rules are
|
|
10870
|
+
* wrapped under that selector. Alternate CSS is wrapped under `.bw_theme_alt`.
|
|
10871
|
+
*
|
|
10872
|
+
* @param {Object} styles - Result of `bw.makeStyles()`
|
|
10873
|
+
* @param {string} [scope] - Scope selector (e.g. '#my-dashboard', '.preview'). Omit for global.
|
|
10874
|
+
* @returns {Element|null} The `<style>` element, or null in Node.js
|
|
10875
|
+
* @category CSS & Styling
|
|
10876
|
+
* @see bw.makeStyles
|
|
10877
|
+
* @see bw.loadStyles
|
|
10878
|
+
* @see bw.clearStyles
|
|
10879
|
+
* @example
|
|
10880
|
+
* var styles = bw.makeStyles({ primary: '#4f46e5' });
|
|
10881
|
+
* bw.applyStyles(styles); // global
|
|
10882
|
+
* bw.applyStyles(styles, '#my-dashboard'); // scoped
|
|
10883
|
+
*/
|
|
10884
|
+
bw.applyStyles = function(styles, scope) {
|
|
10885
|
+
if (!bw._isBrowser) return null;
|
|
10886
|
+
if (!styles || !styles.rules) {
|
|
10887
|
+
_cw('bw.applyStyles: invalid styles object');
|
|
10888
|
+
return null;
|
|
10498
10889
|
}
|
|
10499
10890
|
|
|
10500
|
-
|
|
10501
|
-
|
|
10502
|
-
|
|
10503
|
-
|
|
10504
|
-
|
|
10505
|
-
|
|
10891
|
+
var styleId = _scopeToStyleId(scope);
|
|
10892
|
+
|
|
10893
|
+
// Scope the primary rules if a scope is provided
|
|
10894
|
+
var primaryRules = styles.rules;
|
|
10895
|
+
if (scope) {
|
|
10896
|
+
primaryRules = scopeRulesUnder(primaryRules, scope);
|
|
10506
10897
|
}
|
|
10507
10898
|
|
|
10508
|
-
//
|
|
10509
|
-
var
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
|
|
10515
|
-
|
|
10516
|
-
|
|
10899
|
+
// Wrap alternate rules with .bw_theme_alt
|
|
10900
|
+
var altRules = styles.alternateRules;
|
|
10901
|
+
if (altRules) {
|
|
10902
|
+
if (scope) {
|
|
10903
|
+
// Scoped compound: #scope.bw_theme_alt .bw_card
|
|
10904
|
+
altRules = scopeRulesUnder(altRules, scope + '.bw_theme_alt');
|
|
10905
|
+
} else {
|
|
10906
|
+
// Global: .bw_theme_alt .bw_card
|
|
10907
|
+
altRules = scopeRulesUnder(altRules, '.bw_theme_alt');
|
|
10517
10908
|
}
|
|
10518
|
-
}
|
|
10519
|
-
bw._activeTheme = result;
|
|
10520
|
-
bw._activeThemeMode = 'primary';
|
|
10909
|
+
}
|
|
10521
10910
|
|
|
10522
|
-
|
|
10911
|
+
// Combine primary + alternate into one CSS string
|
|
10912
|
+
var combined = bw.css(primaryRules);
|
|
10913
|
+
if (altRules) {
|
|
10914
|
+
combined += '\n' + bw.css(altRules);
|
|
10915
|
+
}
|
|
10916
|
+
|
|
10917
|
+
return bw.injectCSS(combined, { id: styleId, append: false });
|
|
10523
10918
|
};
|
|
10524
10919
|
|
|
10525
10920
|
/**
|
|
10526
|
-
*
|
|
10527
|
-
*
|
|
10921
|
+
* Generate and apply styles in one call. Convenience wrapper.
|
|
10922
|
+
*
|
|
10923
|
+
* Equivalent to: `bw.applyStyles(bw.makeStyles(config), scope)`
|
|
10528
10924
|
*
|
|
10529
|
-
* @param {
|
|
10530
|
-
* @
|
|
10925
|
+
* @param {Object} [config] - Style configuration (same as `makeStyles`)
|
|
10926
|
+
* @param {string} [scope] - Scope selector (same as `applyStyles`)
|
|
10927
|
+
* @returns {Element|null} The `<style>` element, or null in Node.js
|
|
10531
10928
|
* @category CSS & Styling
|
|
10532
|
-
* @see bw.
|
|
10533
|
-
* @see bw.
|
|
10929
|
+
* @see bw.makeStyles
|
|
10930
|
+
* @see bw.applyStyles
|
|
10534
10931
|
* @example
|
|
10535
|
-
* bw.
|
|
10536
|
-
* bw.
|
|
10537
|
-
* bw.
|
|
10538
|
-
*/
|
|
10539
|
-
bw.
|
|
10540
|
-
|
|
10541
|
-
|
|
10542
|
-
|
|
10543
|
-
|
|
10544
|
-
|
|
10545
|
-
|
|
10546
|
-
|
|
10547
|
-
else if (mode === 'light') wantAlt = !isLight;
|
|
10548
|
-
else if (mode === 'dark') wantAlt = isLight;
|
|
10549
|
-
else wantAlt = false;
|
|
10550
|
-
|
|
10551
|
-
if (wantAlt) {
|
|
10552
|
-
root.classList.add('bw_theme_alt');
|
|
10553
|
-
} else {
|
|
10554
|
-
root.classList.remove('bw_theme_alt');
|
|
10932
|
+
* bw.loadStyles(); // defaults, global
|
|
10933
|
+
* bw.loadStyles({ primary: '#4f46e5' }); // custom, global
|
|
10934
|
+
* bw.loadStyles({ primary: '#4f46e5' }, '#my-dashboard'); // custom, scoped
|
|
10935
|
+
*/
|
|
10936
|
+
bw.loadStyles = function(config, scope) {
|
|
10937
|
+
// Also inject structural CSS first (only once)
|
|
10938
|
+
if (bw._isBrowser) {
|
|
10939
|
+
var existing = document.getElementById('bw_structural');
|
|
10940
|
+
if (!existing) {
|
|
10941
|
+
var structuralCSS = bw.css(getStructuralStyles());
|
|
10942
|
+
bw.injectCSS(structuralCSS, { id: 'bw_structural', append: false });
|
|
10943
|
+
}
|
|
10555
10944
|
}
|
|
10945
|
+
return bw.applyStyles(bw.makeStyles(config), scope);
|
|
10946
|
+
};
|
|
10556
10947
|
|
|
10557
|
-
|
|
10558
|
-
|
|
10948
|
+
/**
|
|
10949
|
+
* Inject the CSS reset (box-sizing, html/body font, reduced-motion).
|
|
10950
|
+
* Idempotent — if already injected, returns the existing `<style>` element.
|
|
10951
|
+
*
|
|
10952
|
+
* @returns {Element|null} The `<style>` element, or null in Node.js
|
|
10953
|
+
* @category CSS & Styling
|
|
10954
|
+
* @see bw.loadStyles
|
|
10955
|
+
* @see bw.clearStyles
|
|
10956
|
+
* @example
|
|
10957
|
+
* bw.loadReset(); // inject once, safe to call multiple times
|
|
10958
|
+
*/
|
|
10959
|
+
bw.loadReset = function() {
|
|
10960
|
+
if (!bw._isBrowser) return null;
|
|
10961
|
+
var existing = document.getElementById('bw_style_reset');
|
|
10962
|
+
if (existing) return existing;
|
|
10963
|
+
return bw.injectCSS(bw.css(getResetStyles()), { id: 'bw_style_reset', append: false });
|
|
10559
10964
|
};
|
|
10560
10965
|
|
|
10561
10966
|
/**
|
|
10562
|
-
* Toggle between primary and alternate
|
|
10967
|
+
* Toggle between primary and alternate palettes.
|
|
10968
|
+
*
|
|
10969
|
+
* Adds/removes the `bw_theme_alt` class on the scoping element.
|
|
10970
|
+
* Without a scope, toggles on `<html>` (global).
|
|
10971
|
+
* With a scope, toggles on the first matching element.
|
|
10563
10972
|
*
|
|
10973
|
+
* @param {string} [scope] - Scope selector (e.g. '#my-dashboard'). Omit for global.
|
|
10564
10974
|
* @returns {string} Active mode after toggle: 'primary' or 'alternate'
|
|
10565
10975
|
* @category CSS & Styling
|
|
10566
|
-
* @see bw.
|
|
10567
|
-
* @see bw.
|
|
10976
|
+
* @see bw.applyStyles
|
|
10977
|
+
* @see bw.clearStyles
|
|
10568
10978
|
* @example
|
|
10569
|
-
* bw.
|
|
10979
|
+
* bw.toggleStyles(); // global toggle on <html>
|
|
10980
|
+
* bw.toggleStyles('#my-dashboard'); // scoped toggle
|
|
10570
10981
|
*/
|
|
10571
|
-
bw.
|
|
10572
|
-
|
|
10573
|
-
|
|
10982
|
+
bw.toggleStyles = function(scope) {
|
|
10983
|
+
if (!bw._isBrowser) return 'primary';
|
|
10984
|
+
var target;
|
|
10985
|
+
if (scope) {
|
|
10986
|
+
var els = bw.$(scope);
|
|
10987
|
+
target = els[0];
|
|
10988
|
+
} else {
|
|
10989
|
+
target = document.documentElement;
|
|
10990
|
+
}
|
|
10991
|
+
if (!target) return 'primary';
|
|
10992
|
+
|
|
10993
|
+
var hasAlt = target.classList.contains('bw_theme_alt');
|
|
10994
|
+
if (hasAlt) {
|
|
10995
|
+
target.classList.remove('bw_theme_alt');
|
|
10996
|
+
return 'primary';
|
|
10997
|
+
} else {
|
|
10998
|
+
target.classList.add('bw_theme_alt');
|
|
10999
|
+
return 'alternate';
|
|
11000
|
+
}
|
|
10574
11001
|
};
|
|
10575
11002
|
|
|
10576
11003
|
/**
|
|
10577
|
-
* Remove
|
|
10578
|
-
*
|
|
10579
|
-
*
|
|
11004
|
+
* Remove injected styles for a given scope.
|
|
11005
|
+
*
|
|
11006
|
+
* Finds the `<style>` element by id and removes it. Also removes
|
|
11007
|
+
* the `bw_theme_alt` class from the relevant element.
|
|
10580
11008
|
*
|
|
11009
|
+
* @param {string} [scope] - Scope selector. Omit to remove global styles.
|
|
10581
11010
|
* @category CSS & Styling
|
|
10582
|
-
* @see bw.
|
|
11011
|
+
* @see bw.applyStyles
|
|
11012
|
+
* @see bw.loadStyles
|
|
10583
11013
|
* @example
|
|
10584
|
-
* bw.
|
|
10585
|
-
* bw.
|
|
10586
|
-
|
|
10587
|
-
|
|
10588
|
-
|
|
10589
|
-
|
|
10590
|
-
|
|
10591
|
-
|
|
10592
|
-
|
|
10593
|
-
|
|
11014
|
+
* bw.clearStyles(); // remove global styles
|
|
11015
|
+
* bw.clearStyles('#my-dashboard'); // remove scoped styles
|
|
11016
|
+
* bw.clearStyles('reset'); // remove the CSS reset
|
|
11017
|
+
*/
|
|
11018
|
+
bw.clearStyles = function(scope) {
|
|
11019
|
+
if (!bw._isBrowser) return;
|
|
11020
|
+
var styleId = _scopeToStyleId(scope);
|
|
11021
|
+
var el = document.getElementById(styleId);
|
|
11022
|
+
if (el) el.remove();
|
|
11023
|
+
|
|
11024
|
+
// Also remove bw_theme_alt from the relevant element
|
|
11025
|
+
if (scope && scope !== 'reset' && scope !== 'global') {
|
|
11026
|
+
var targets = bw.$(scope);
|
|
11027
|
+
if (targets[0]) targets[0].classList.remove('bw_theme_alt');
|
|
11028
|
+
} else if (!scope || scope === 'global') {
|
|
11029
|
+
document.documentElement.classList.remove('bw_theme_alt');
|
|
10594
11030
|
}
|
|
10595
|
-
bw._activeTheme = null;
|
|
10596
|
-
bw._activeThemeMode = 'primary';
|
|
10597
11031
|
};
|
|
10598
11032
|
|
|
10599
11033
|
// Expose color utility functions on bw namespace
|
|
@@ -10816,10 +11250,15 @@
|
|
|
10816
11250
|
* @param {Object} config - Table configuration
|
|
10817
11251
|
* @param {Array<Object>} config.data - Array of row objects to display
|
|
10818
11252
|
* @param {Array<Object>} [config.columns] - Column definitions with key, label, render
|
|
10819
|
-
* @param {string} [config.className='
|
|
11253
|
+
* @param {string} [config.className=''] - Additional CSS classes for table element
|
|
10820
11254
|
* @param {boolean} [config.sortable=true] - Enable click-to-sort headers
|
|
10821
11255
|
* @param {Function} [config.onSort] - Sort callback (column, direction)
|
|
10822
|
-
* @
|
|
11256
|
+
* @param {boolean} [config.selectable=false] - Enable row selection on click
|
|
11257
|
+
* @param {Function} [config.onRowClick] - Row click callback (row, index, event)
|
|
11258
|
+
* @param {number} [config.pageSize] - Rows per page (enables pagination when set)
|
|
11259
|
+
* @param {number} [config.currentPage=1] - Current page number (1-based)
|
|
11260
|
+
* @param {Function} [config.onPageChange] - Page change callback (newPage)
|
|
11261
|
+
* @returns {Object} TACO object for table (with optional pagination controls)
|
|
10823
11262
|
* @category Component Builders
|
|
10824
11263
|
* @see bw.makeDataTable
|
|
10825
11264
|
* @example
|
|
@@ -10831,7 +11270,12 @@
|
|
|
10831
11270
|
* columns: [
|
|
10832
11271
|
* { key: 'name', label: 'Name' },
|
|
10833
11272
|
* { key: 'age', label: 'Age' }
|
|
10834
|
-
* ]
|
|
11273
|
+
* ],
|
|
11274
|
+
* selectable: true,
|
|
11275
|
+
* onRowClick: function(row, i) { console.log('clicked', row.name); },
|
|
11276
|
+
* pageSize: 10,
|
|
11277
|
+
* currentPage: 1,
|
|
11278
|
+
* onPageChange: function(page) { console.log('page', page); }
|
|
10835
11279
|
* });
|
|
10836
11280
|
*/
|
|
10837
11281
|
bw.makeTable = function(config) {
|
|
@@ -10844,41 +11288,47 @@
|
|
|
10844
11288
|
sortable = true,
|
|
10845
11289
|
onSort,
|
|
10846
11290
|
sortColumn,
|
|
10847
|
-
sortDirection = 'asc'
|
|
11291
|
+
sortDirection = 'asc',
|
|
11292
|
+
selectable = false,
|
|
11293
|
+
onRowClick,
|
|
11294
|
+
pageSize,
|
|
11295
|
+
currentPage = 1,
|
|
11296
|
+
onPageChange
|
|
10848
11297
|
} = config;
|
|
10849
11298
|
|
|
10850
|
-
// Build class list: always include bw_table, add striped/hover, append user className
|
|
11299
|
+
// Build class list: always include bw_table, add striped/hover/selectable, append user className
|
|
10851
11300
|
let cls = 'bw_table';
|
|
10852
11301
|
if (striped) cls += ' bw_table_striped';
|
|
10853
|
-
if (hover) cls += ' bw_table_hover';
|
|
11302
|
+
if (hover || selectable) cls += ' bw_table_hover';
|
|
11303
|
+
if (selectable) cls += ' bw_table_selectable';
|
|
10854
11304
|
if (className) cls += ' ' + className;
|
|
10855
11305
|
cls = cls.trim();
|
|
10856
|
-
|
|
11306
|
+
|
|
10857
11307
|
// Auto-detect columns if not provided
|
|
10858
|
-
const cols = columns || (data.length > 0
|
|
10859
|
-
?
|
|
11308
|
+
const cols = columns || (data.length > 0
|
|
11309
|
+
? _keys(data[0]).map(key => ({ key, label: key }))
|
|
10860
11310
|
: []);
|
|
10861
|
-
|
|
11311
|
+
|
|
10862
11312
|
// Current sort state
|
|
10863
11313
|
let currentSortColumn = sortColumn || null;
|
|
10864
11314
|
let currentSortDirection = sortDirection;
|
|
10865
|
-
|
|
11315
|
+
|
|
10866
11316
|
// Sort data if column specified
|
|
10867
11317
|
let sortedData = [...data];
|
|
10868
11318
|
if (currentSortColumn) {
|
|
10869
11319
|
sortedData.sort((a, b) => {
|
|
10870
11320
|
const aVal = a[currentSortColumn];
|
|
10871
11321
|
const bVal = b[currentSortColumn];
|
|
10872
|
-
|
|
11322
|
+
|
|
10873
11323
|
// Handle different types
|
|
10874
|
-
if (
|
|
11324
|
+
if (_is(aVal, 'number') && _is(bVal, 'number')) {
|
|
10875
11325
|
return currentSortDirection === 'asc' ? aVal - bVal : bVal - aVal;
|
|
10876
11326
|
}
|
|
10877
|
-
|
|
11327
|
+
|
|
10878
11328
|
// String comparison
|
|
10879
11329
|
const aStr = String(aVal || '').toLowerCase();
|
|
10880
11330
|
const bStr = String(bVal || '').toLowerCase();
|
|
10881
|
-
|
|
11331
|
+
|
|
10882
11332
|
if (currentSortDirection === 'asc') {
|
|
10883
11333
|
return aStr.localeCompare(bStr);
|
|
10884
11334
|
} else {
|
|
@@ -10886,23 +11336,32 @@
|
|
|
10886
11336
|
}
|
|
10887
11337
|
});
|
|
10888
11338
|
}
|
|
10889
|
-
|
|
11339
|
+
|
|
11340
|
+
// Pagination
|
|
11341
|
+
const totalRows = sortedData.length;
|
|
11342
|
+
const totalPages = pageSize ? Math.max(1, Math.ceil(totalRows / pageSize)) : 1;
|
|
11343
|
+
const page = Math.max(1, Math.min(currentPage, totalPages));
|
|
11344
|
+
if (pageSize) {
|
|
11345
|
+
const start = (page - 1) * pageSize;
|
|
11346
|
+
sortedData = sortedData.slice(start, start + pageSize);
|
|
11347
|
+
}
|
|
11348
|
+
|
|
10890
11349
|
// Create sort handler
|
|
10891
11350
|
const handleSort = (column) => {
|
|
10892
11351
|
if (!sortable) return;
|
|
10893
|
-
|
|
11352
|
+
|
|
10894
11353
|
if (currentSortColumn === column) {
|
|
10895
11354
|
currentSortDirection = currentSortDirection === 'asc' ? 'desc' : 'asc';
|
|
10896
11355
|
} else {
|
|
10897
11356
|
currentSortColumn = column;
|
|
10898
11357
|
currentSortDirection = 'asc';
|
|
10899
11358
|
}
|
|
10900
|
-
|
|
11359
|
+
|
|
10901
11360
|
if (onSort) {
|
|
10902
11361
|
onSort(column, currentSortDirection);
|
|
10903
11362
|
}
|
|
10904
11363
|
};
|
|
10905
|
-
|
|
11364
|
+
|
|
10906
11365
|
// Build table header
|
|
10907
11366
|
const thead = {
|
|
10908
11367
|
t: 'thead',
|
|
@@ -10925,24 +11384,87 @@
|
|
|
10925
11384
|
}))
|
|
10926
11385
|
}
|
|
10927
11386
|
};
|
|
10928
|
-
|
|
10929
|
-
// Build table body
|
|
11387
|
+
|
|
11388
|
+
// Build table body with selectable/onRowClick support
|
|
10930
11389
|
const tbody = {
|
|
10931
11390
|
t: 'tbody',
|
|
10932
|
-
c: sortedData.map(row =>
|
|
10933
|
-
|
|
10934
|
-
|
|
10935
|
-
|
|
10936
|
-
|
|
10937
|
-
|
|
10938
|
-
|
|
11391
|
+
c: sortedData.map((row, idx) => {
|
|
11392
|
+
const globalIdx = pageSize ? (page - 1) * pageSize + idx : idx;
|
|
11393
|
+
const rowAttrs = {};
|
|
11394
|
+
if (selectable || onRowClick) {
|
|
11395
|
+
rowAttrs.style = 'cursor:pointer;';
|
|
11396
|
+
rowAttrs.onclick = function(e) {
|
|
11397
|
+
if (selectable) {
|
|
11398
|
+
// Toggle selected class on this row
|
|
11399
|
+
var tr = e.currentTarget;
|
|
11400
|
+
tr.classList.toggle('bw_table_row_selected');
|
|
11401
|
+
}
|
|
11402
|
+
if (onRowClick) {
|
|
11403
|
+
onRowClick(row, globalIdx, e);
|
|
11404
|
+
}
|
|
11405
|
+
};
|
|
11406
|
+
}
|
|
11407
|
+
return {
|
|
11408
|
+
t: 'tr',
|
|
11409
|
+
a: rowAttrs,
|
|
11410
|
+
c: cols.map(col => ({
|
|
11411
|
+
t: 'td',
|
|
11412
|
+
c: col.render ? col.render(row[col.key], row) : String(row[col.key] || '')
|
|
11413
|
+
}))
|
|
11414
|
+
};
|
|
11415
|
+
})
|
|
10939
11416
|
};
|
|
10940
|
-
|
|
10941
|
-
|
|
11417
|
+
|
|
11418
|
+
const table = {
|
|
10942
11419
|
t: 'table',
|
|
10943
11420
|
a: { class: cls },
|
|
10944
11421
|
c: [thead, tbody]
|
|
10945
11422
|
};
|
|
11423
|
+
|
|
11424
|
+
// If no pagination, return table directly
|
|
11425
|
+
if (!pageSize) return table;
|
|
11426
|
+
|
|
11427
|
+
// Build pagination controls
|
|
11428
|
+
const pageButtons = [];
|
|
11429
|
+
// Previous button
|
|
11430
|
+
pageButtons.push({
|
|
11431
|
+
t: 'button',
|
|
11432
|
+
a: {
|
|
11433
|
+
class: 'bw_btn bw_btn_sm',
|
|
11434
|
+
disabled: page <= 1 ? 'disabled' : undefined,
|
|
11435
|
+
onclick: page > 1 && onPageChange ? function() { onPageChange(page - 1); } : undefined
|
|
11436
|
+
},
|
|
11437
|
+
c: 'Prev'
|
|
11438
|
+
});
|
|
11439
|
+
// Page info
|
|
11440
|
+
pageButtons.push({
|
|
11441
|
+
t: 'span',
|
|
11442
|
+
a: { style: 'margin:0 0.5rem;font-size:0.875rem;' },
|
|
11443
|
+
c: 'Page ' + page + ' of ' + totalPages
|
|
11444
|
+
});
|
|
11445
|
+
// Next button
|
|
11446
|
+
pageButtons.push({
|
|
11447
|
+
t: 'button',
|
|
11448
|
+
a: {
|
|
11449
|
+
class: 'bw_btn bw_btn_sm',
|
|
11450
|
+
disabled: page >= totalPages ? 'disabled' : undefined,
|
|
11451
|
+
onclick: page < totalPages && onPageChange ? function() { onPageChange(page + 1); } : undefined
|
|
11452
|
+
},
|
|
11453
|
+
c: 'Next'
|
|
11454
|
+
});
|
|
11455
|
+
|
|
11456
|
+
return {
|
|
11457
|
+
t: 'div',
|
|
11458
|
+
a: { class: 'bw_table_paginated' },
|
|
11459
|
+
c: [
|
|
11460
|
+
table,
|
|
11461
|
+
{
|
|
11462
|
+
t: 'div',
|
|
11463
|
+
a: { class: 'bw_table_pagination', style: 'display:flex;align-items:center;justify-content:flex-end;padding:0.5rem 0;gap:0.25rem;' },
|
|
11464
|
+
c: pageButtons
|
|
11465
|
+
}
|
|
11466
|
+
]
|
|
11467
|
+
};
|
|
10946
11468
|
};
|
|
10947
11469
|
|
|
10948
11470
|
/**
|
|
@@ -10981,7 +11503,7 @@
|
|
|
10981
11503
|
bw.makeTableFromArray = function(config) {
|
|
10982
11504
|
const { data = [], headerRow = true, columns, ...rest } = config;
|
|
10983
11505
|
|
|
10984
|
-
if (!
|
|
11506
|
+
if (!_isA(data) || data.length === 0) {
|
|
10985
11507
|
return bw.makeTable({ data: [], columns: columns || [], ...rest });
|
|
10986
11508
|
}
|
|
10987
11509
|
|
|
@@ -11063,7 +11585,7 @@
|
|
|
11063
11585
|
className = ''
|
|
11064
11586
|
} = config;
|
|
11065
11587
|
|
|
11066
|
-
if (!
|
|
11588
|
+
if (!_isA(data) || data.length === 0) {
|
|
11067
11589
|
return { t: 'div', a: { class: ('bw_bar_chart_container ' + className).trim() }, c: '' };
|
|
11068
11590
|
}
|
|
11069
11591
|
|
|
@@ -11212,7 +11734,7 @@
|
|
|
11212
11734
|
*/
|
|
11213
11735
|
bw.render = function(element, position, taco) {
|
|
11214
11736
|
// Get target element
|
|
11215
|
-
const targetEl =
|
|
11737
|
+
const targetEl = _is(element, 'string')
|
|
11216
11738
|
? document.querySelector(element)
|
|
11217
11739
|
: element;
|
|
11218
11740
|
|
|
@@ -11362,7 +11884,7 @@
|
|
|
11362
11884
|
setContent(content) {
|
|
11363
11885
|
this._taco.c = content;
|
|
11364
11886
|
if (this.element) {
|
|
11365
|
-
if (
|
|
11887
|
+
if (_is(content, 'string')) {
|
|
11366
11888
|
this.element.textContent = content;
|
|
11367
11889
|
} else {
|
|
11368
11890
|
// Re-render for complex content
|