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
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
/*! bitwrench-lean v2.0.
|
|
1
|
+
/*! bitwrench-lean 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
|
function _arrayLikeToArray(r, a) {
|
|
9
10
|
(null == a || a > r.length) && (a = r.length);
|
|
10
11
|
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
|
|
@@ -189,14 +190,14 @@
|
|
|
189
190
|
*/
|
|
190
191
|
|
|
191
192
|
var VERSION_INFO = {
|
|
192
|
-
version: '2.0.
|
|
193
|
+
version: '2.0.18',
|
|
193
194
|
name: 'bitwrench',
|
|
194
195
|
description: 'A library for javascript UI functions.',
|
|
195
196
|
license: 'BSD-2-Clause',
|
|
196
197
|
homepage: 'https://deftio.github.com/bitwrench/pages',
|
|
197
198
|
repository: 'git+https://github.com/deftio/bitwrench.git',
|
|
198
199
|
author: 'manu a. chatterjee <deftio@deftio.com> (https://deftio.com/)',
|
|
199
|
-
buildDate: '2026-03-
|
|
200
|
+
buildDate: '2026-03-17T00:50:09.505Z'
|
|
200
201
|
};
|
|
201
202
|
|
|
202
203
|
/**
|
|
@@ -485,13 +486,16 @@
|
|
|
485
486
|
*/
|
|
486
487
|
function deriveShades(hex) {
|
|
487
488
|
var rgb = colorParse(hex);
|
|
489
|
+
// For light input colors (L > 75), mixing toward white produces invisible borders.
|
|
490
|
+
// Darken instead so borders remain visible against light backgrounds.
|
|
491
|
+
var borderColor = hexToHsl(hex)[2] > 75 ? adjustLightness(hex, -18) : mixColor(hex, '#ffffff', 0.60);
|
|
488
492
|
return {
|
|
489
493
|
base: hex,
|
|
490
494
|
hover: adjustLightness(hex, -10),
|
|
491
495
|
active: adjustLightness(hex, -15),
|
|
492
496
|
light: mixColor(hex, '#ffffff', 0.85),
|
|
493
497
|
darkText: adjustLightness(hex, -40),
|
|
494
|
-
border:
|
|
498
|
+
border: borderColor,
|
|
495
499
|
focus: 'rgba(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ',0.25)',
|
|
496
500
|
textOn: textOnColor(hex)
|
|
497
501
|
};
|
|
@@ -550,18 +554,26 @@
|
|
|
550
554
|
alt.secondary = deriveAlternateSeed(config.secondary);
|
|
551
555
|
alt.tertiary = config.tertiary ? deriveAlternateSeed(config.tertiary) : alt.primary;
|
|
552
556
|
|
|
553
|
-
// Derive alternate surface colors from primary hue
|
|
557
|
+
// Derive alternate surface colors from primary hue.
|
|
558
|
+
// Check actual page surface brightness (not seed color brightness) to decide
|
|
559
|
+
// whether alternate should be dark or light. The page surface is what the
|
|
560
|
+
// user sees; seeds can be dark while the page is still light (default L=96).
|
|
554
561
|
var priHsl = hexToHsl(config.primary);
|
|
555
562
|
var h = priHsl[0];
|
|
556
|
-
var
|
|
563
|
+
var primarySurface = config.surface || hslToHex([h, 8, 96]);
|
|
564
|
+
var isLight = relativeLuminance(primarySurface) > 0.179;
|
|
557
565
|
if (isLight) {
|
|
558
|
-
//
|
|
566
|
+
// Page surface is light → alternate needs dark surfaces
|
|
559
567
|
alt.light = hslToHex([h, Math.min(priHsl[1], 15), 15]);
|
|
560
568
|
alt.dark = hslToHex([h, 5, 88]);
|
|
569
|
+
alt.surface = hslToHex([h, 12, 18]);
|
|
570
|
+
alt.background = hslToHex([h, 10, 14]);
|
|
561
571
|
} else {
|
|
562
|
-
//
|
|
572
|
+
// Page surface is dark → alternate needs light surfaces
|
|
563
573
|
alt.light = hslToHex([h, Math.min(priHsl[1], 10), 96]);
|
|
564
574
|
alt.dark = hslToHex([h, 10, 18]);
|
|
575
|
+
alt.surface = hslToHex([h, 8, 96]);
|
|
576
|
+
alt.background = hslToHex([h, 6, 98]);
|
|
565
577
|
}
|
|
566
578
|
|
|
567
579
|
// Semantic colors: harmonize toward primary, then invert for alternate
|
|
@@ -610,10 +622,16 @@
|
|
|
610
622
|
var darkBase = config.dark || hslToHex([h, 10, 13]);
|
|
611
623
|
|
|
612
624
|
// Background & surface tokens — tinted with primary hue for theme personality.
|
|
613
|
-
//
|
|
625
|
+
// Saturation high enough that the hue is visible (each theme feels distinct)
|
|
626
|
+
// but low enough to stay neutral and readable.
|
|
614
627
|
// User can override with config.background / config.surface.
|
|
615
|
-
var bgBase = config.background || hslToHex([h,
|
|
616
|
-
var surfBase = config.surface || hslToHex([h,
|
|
628
|
+
var bgBase = config.background || hslToHex([h, 22, 96]);
|
|
629
|
+
var surfBase = config.surface || hslToHex([h, 25, 94]);
|
|
630
|
+
|
|
631
|
+
// surfaceAlt: subtle background variant for striped rows, hover states, headers.
|
|
632
|
+
// Slightly lighter than surface in dark mode, slightly darker in light mode.
|
|
633
|
+
var surfHsl = hexToHsl(surfBase);
|
|
634
|
+
var surfAlt = surfHsl[2] <= 50 ? hslToHex([surfHsl[0], surfHsl[1], Math.min(surfHsl[2] + 8, 100)]) : hslToHex([surfHsl[0], surfHsl[1], Math.max(surfHsl[2] - 3, 0)]);
|
|
617
635
|
var palette = {
|
|
618
636
|
primary: deriveShades(config.primary),
|
|
619
637
|
secondary: deriveShades(config.secondary),
|
|
@@ -625,7 +643,8 @@
|
|
|
625
643
|
light: deriveShades(lightBase),
|
|
626
644
|
dark: deriveShades(darkBase),
|
|
627
645
|
background: bgBase,
|
|
628
|
-
surface: surfBase
|
|
646
|
+
surface: surfBase,
|
|
647
|
+
surfaceAlt: surfAlt
|
|
629
648
|
};
|
|
630
649
|
return palette;
|
|
631
650
|
}
|
|
@@ -650,27 +669,28 @@
|
|
|
650
669
|
5: '1.5rem',
|
|
651
670
|
// 24px
|
|
652
671
|
6: '2rem'};
|
|
672
|
+
var _S = SPACING_SCALE;
|
|
653
673
|
var SPACING_PRESETS = {
|
|
654
674
|
compact: {
|
|
655
|
-
btn:
|
|
656
|
-
card:
|
|
657
|
-
alert:
|
|
658
|
-
cell:
|
|
659
|
-
input:
|
|
675
|
+
btn: _S[1] + ' ' + _S[3],
|
|
676
|
+
card: _S[3] + ' ' + _S[4],
|
|
677
|
+
alert: _S[2] + ' ' + _S[4],
|
|
678
|
+
cell: _S[2] + ' ' + _S[3],
|
|
679
|
+
input: _S[1] + ' ' + _S[3]
|
|
660
680
|
},
|
|
661
681
|
normal: {
|
|
662
|
-
btn:
|
|
663
|
-
card:
|
|
664
|
-
alert:
|
|
665
|
-
cell:
|
|
666
|
-
input:
|
|
682
|
+
btn: _S[2] + ' ' + _S[4],
|
|
683
|
+
card: _S[5] + ' ' + _S[5],
|
|
684
|
+
alert: _S[3] + ' ' + _S[5],
|
|
685
|
+
cell: _S[3] + ' ' + _S[4],
|
|
686
|
+
input: _S[2] + ' ' + _S[3]
|
|
667
687
|
},
|
|
668
688
|
spacious: {
|
|
669
|
-
btn:
|
|
670
|
-
card:
|
|
671
|
-
alert:
|
|
672
|
-
cell:
|
|
673
|
-
input:
|
|
689
|
+
btn: _S[3] + ' ' + _S[5],
|
|
690
|
+
card: _S[6] + ' ' + _S[6],
|
|
691
|
+
alert: _S[4] + ' ' + _S[5],
|
|
692
|
+
cell: _S[4] + ' ' + _S[5],
|
|
693
|
+
input: _S[3] + ' ' + _S[4]
|
|
674
694
|
}
|
|
675
695
|
};
|
|
676
696
|
var RADIUS_PRESETS = {
|
|
@@ -812,68 +832,13 @@
|
|
|
812
832
|
* Built-in theme presets — named color combinations
|
|
813
833
|
* Each preset provides primary, secondary, and tertiary seed colors.
|
|
814
834
|
*/
|
|
815
|
-
var THEME_PRESETS = {
|
|
816
|
-
|
|
817
|
-
primary:
|
|
818
|
-
secondary:
|
|
819
|
-
tertiary:
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
primary: '#0077b6',
|
|
823
|
-
secondary: '#90e0ef',
|
|
824
|
-
tertiary: '#00b4d8'
|
|
825
|
-
},
|
|
826
|
-
sunset: {
|
|
827
|
-
primary: '#e76f51',
|
|
828
|
-
secondary: '#264653',
|
|
829
|
-
tertiary: '#e9c46a'
|
|
830
|
-
},
|
|
831
|
-
forest: {
|
|
832
|
-
primary: '#2d6a4f',
|
|
833
|
-
secondary: '#95d5b2',
|
|
834
|
-
tertiary: '#52b788'
|
|
835
|
-
},
|
|
836
|
-
slate: {
|
|
837
|
-
primary: '#343a40',
|
|
838
|
-
secondary: '#adb5bd',
|
|
839
|
-
tertiary: '#6c757d'
|
|
840
|
-
},
|
|
841
|
-
rose: {
|
|
842
|
-
primary: '#e11d48',
|
|
843
|
-
secondary: '#fda4af',
|
|
844
|
-
tertiary: '#fb7185'
|
|
845
|
-
},
|
|
846
|
-
indigo: {
|
|
847
|
-
primary: '#4f46e5',
|
|
848
|
-
secondary: '#a5b4fc',
|
|
849
|
-
tertiary: '#818cf8'
|
|
850
|
-
},
|
|
851
|
-
amber: {
|
|
852
|
-
primary: '#d97706',
|
|
853
|
-
secondary: '#fbbf24',
|
|
854
|
-
tertiary: '#f59e0b'
|
|
855
|
-
},
|
|
856
|
-
emerald: {
|
|
857
|
-
primary: '#059669',
|
|
858
|
-
secondary: '#6ee7b7',
|
|
859
|
-
tertiary: '#34d399'
|
|
860
|
-
},
|
|
861
|
-
nord: {
|
|
862
|
-
primary: '#5e81ac',
|
|
863
|
-
secondary: '#88c0d0',
|
|
864
|
-
tertiary: '#81a1c1'
|
|
865
|
-
},
|
|
866
|
-
coral: {
|
|
867
|
-
primary: '#ef6461',
|
|
868
|
-
secondary: '#4a7c7e',
|
|
869
|
-
tertiary: '#e8a87c'
|
|
870
|
-
},
|
|
871
|
-
midnight: {
|
|
872
|
-
primary: '#1e3a5f',
|
|
873
|
-
secondary: '#7c8db5',
|
|
874
|
-
tertiary: '#3d5a80'
|
|
875
|
-
}
|
|
876
|
-
};
|
|
835
|
+
var THEME_PRESETS = Object.fromEntries([['teal', '#006666', '#6c757d', '#006666'], ['ocean', '#0077b6', '#90e0ef', '#00b4d8'], ['sunset', '#e76f51', '#264653', '#e9c46a'], ['forest', '#2d6a4f', '#95d5b2', '#52b788'], ['slate', '#343a40', '#adb5bd', '#6c757d'], ['rose', '#e11d48', '#fda4af', '#fb7185'], ['indigo', '#4f46e5', '#a5b4fc', '#818cf8'], ['amber', '#d97706', '#fbbf24', '#f59e0b'], ['emerald', '#059669', '#6ee7b7', '#34d399'], ['nord', '#5e81ac', '#88c0d0', '#81a1c1'], ['coral', '#ef6461', '#4a7c7e', '#e8a87c'], ['midnight', '#1e3a5f', '#7c8db5', '#3d5a80']].map(function (e) {
|
|
836
|
+
return [e[0], {
|
|
837
|
+
primary: e[1],
|
|
838
|
+
secondary: e[2],
|
|
839
|
+
tertiary: e[3]
|
|
840
|
+
}];
|
|
841
|
+
}));
|
|
877
842
|
|
|
878
843
|
/**
|
|
879
844
|
* Resolve layout config to spacing, radius, typeScale, elevation, and motion objects.
|
|
@@ -921,6 +886,7 @@
|
|
|
921
886
|
}).join(', ');
|
|
922
887
|
return '.' + name + ' ' + sel;
|
|
923
888
|
}
|
|
889
|
+
var _sx = scopeSelector;
|
|
924
890
|
|
|
925
891
|
// =========================================================================
|
|
926
892
|
// Themed CSS generators
|
|
@@ -929,12 +895,12 @@
|
|
|
929
895
|
function generateTypographyThemed(scope, palette, layout) {
|
|
930
896
|
var mot = layout.motion;
|
|
931
897
|
var rules = {};
|
|
932
|
-
rules[
|
|
898
|
+
rules[_sx(scope, 'a')] = {
|
|
933
899
|
'color': palette.primary.base,
|
|
934
900
|
'text-decoration': 'none',
|
|
935
901
|
'transition': 'color ' + mot.fast + ' ' + mot.easing
|
|
936
902
|
};
|
|
937
|
-
rules[
|
|
903
|
+
rules[_sx(scope, 'a:hover')] = {
|
|
938
904
|
'color': palette.primary.hover,
|
|
939
905
|
'text-decoration': 'underline'
|
|
940
906
|
};
|
|
@@ -946,11 +912,11 @@
|
|
|
946
912
|
var rd = layout.radius;
|
|
947
913
|
|
|
948
914
|
// Base button (only when scoped — unscoped uses defaultStyles)
|
|
949
|
-
rules[
|
|
915
|
+
rules[_sx(scope, '.bw_btn')] = {
|
|
950
916
|
'padding': sp.btn,
|
|
951
917
|
'border-radius': rd.btn
|
|
952
918
|
};
|
|
953
|
-
rules[
|
|
919
|
+
rules[_sx(scope, '.bw_btn:focus-visible')] = {
|
|
954
920
|
'outline': '2px solid currentColor',
|
|
955
921
|
'outline-offset': '2px',
|
|
956
922
|
'box-shadow': '0 0 0 3px ' + palette.primary.focus
|
|
@@ -959,12 +925,12 @@
|
|
|
959
925
|
// Variant colors handled by palette class on component root
|
|
960
926
|
|
|
961
927
|
// Size variants (structural, reuse layout radius)
|
|
962
|
-
rules[
|
|
928
|
+
rules[_sx(scope, '.bw_btn_lg')] = {
|
|
963
929
|
'padding': '0.625rem 1.5rem',
|
|
964
930
|
'font-size': '1rem',
|
|
965
931
|
'border-radius': rd.btn === '50rem' ? '50rem' : parseInt(rd.btn) + 2 + 'px'
|
|
966
932
|
};
|
|
967
|
-
rules[
|
|
933
|
+
rules[_sx(scope, '.bw_btn_sm')] = {
|
|
968
934
|
'padding': '0.25rem 0.75rem',
|
|
969
935
|
'font-size': '0.8125rem',
|
|
970
936
|
'border-radius': rd.btn === '50rem' ? '50rem' : Math.max(parseInt(rd.btn) - 1, 0) + 'px'
|
|
@@ -975,7 +941,7 @@
|
|
|
975
941
|
var rules = {};
|
|
976
942
|
var sp = layout.spacing;
|
|
977
943
|
var rd = layout.radius;
|
|
978
|
-
rules[
|
|
944
|
+
rules[_sx(scope, '.bw_alert')] = {
|
|
979
945
|
'padding': sp.alert,
|
|
980
946
|
'border-radius': rd.alert
|
|
981
947
|
};
|
|
@@ -993,38 +959,38 @@
|
|
|
993
959
|
var rd = layout.radius;
|
|
994
960
|
var elev = layout.elevation;
|
|
995
961
|
var motion = layout.motion;
|
|
996
|
-
rules[
|
|
962
|
+
rules[_sx(scope, '.bw_card')] = {
|
|
997
963
|
'background-color': palette.surface || '#fff',
|
|
998
964
|
'border': '1px solid ' + palette.light.border,
|
|
999
965
|
'border-radius': rd.card,
|
|
1000
966
|
'box-shadow': elev.sm,
|
|
1001
967
|
'transition': 'box-shadow ' + motion.normal + ' ' + motion.easing + ', transform ' + motion.normal + ' ' + motion.easing
|
|
1002
968
|
};
|
|
1003
|
-
rules[
|
|
969
|
+
rules[_sx(scope, '.bw_card:hover')] = {
|
|
1004
970
|
'box-shadow': elev.md
|
|
1005
971
|
};
|
|
1006
|
-
rules[
|
|
972
|
+
rules[_sx(scope, '.bw_card_hoverable:hover')] = {
|
|
1007
973
|
'box-shadow': elev.lg
|
|
1008
974
|
};
|
|
1009
|
-
rules[
|
|
975
|
+
rules[_sx(scope, '.bw_card_body')] = {
|
|
1010
976
|
'padding': sp.card
|
|
1011
977
|
};
|
|
1012
|
-
rules[
|
|
978
|
+
rules[_sx(scope, '.bw_card_header')] = {
|
|
1013
979
|
'padding': sp.card.split(' ').map(function (v) {
|
|
1014
980
|
return (parseFloat(v) * 0.7).toFixed(3).replace(/\.?0+$/, '') + 'rem';
|
|
1015
981
|
}).join(' '),
|
|
1016
|
-
'background-color': palette.
|
|
982
|
+
'background-color': palette.surfaceAlt,
|
|
1017
983
|
'border-bottom': '1px solid ' + palette.light.border
|
|
1018
984
|
};
|
|
1019
|
-
rules[
|
|
1020
|
-
'background-color': palette.
|
|
985
|
+
rules[_sx(scope, '.bw_card_footer')] = {
|
|
986
|
+
'background-color': palette.surfaceAlt,
|
|
1021
987
|
'border-top': '1px solid ' + palette.light.border,
|
|
1022
988
|
'color': palette.secondary.base
|
|
1023
989
|
};
|
|
1024
|
-
rules[
|
|
990
|
+
rules[_sx(scope, '.bw_card_title')] = {
|
|
1025
991
|
'color': palette.dark.base
|
|
1026
992
|
};
|
|
1027
|
-
rules[
|
|
993
|
+
rules[_sx(scope, '.bw_card_subtitle')] = {
|
|
1028
994
|
'color': palette.secondary.base
|
|
1029
995
|
};
|
|
1030
996
|
|
|
@@ -1036,101 +1002,104 @@
|
|
|
1036
1002
|
var rules = {};
|
|
1037
1003
|
var sp = layout.spacing;
|
|
1038
1004
|
var rd = layout.radius;
|
|
1039
|
-
rules[
|
|
1005
|
+
rules[_sx(scope, '.bw_form_control')] = {
|
|
1040
1006
|
'padding': sp.input,
|
|
1041
1007
|
'border-radius': rd.input,
|
|
1042
1008
|
'color': palette.dark.base,
|
|
1043
1009
|
'background-color': palette.surface || '#fff',
|
|
1044
1010
|
'border-color': palette.light.border
|
|
1045
1011
|
};
|
|
1046
|
-
rules[
|
|
1012
|
+
rules[_sx(scope, '.bw_form_control:focus')] = {
|
|
1047
1013
|
'border-color': palette.primary.border,
|
|
1048
1014
|
'outline': '2px solid ' + palette.primary.base,
|
|
1049
1015
|
'outline-offset': '-1px',
|
|
1050
1016
|
'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
|
|
1051
1017
|
};
|
|
1052
|
-
rules[
|
|
1018
|
+
rules[_sx(scope, '.bw_form_control::placeholder')] = {
|
|
1053
1019
|
'color': palette.secondary.base
|
|
1054
1020
|
};
|
|
1055
|
-
rules[
|
|
1021
|
+
rules[_sx(scope, '.bw_form_label')] = {
|
|
1056
1022
|
'color': palette.dark.base
|
|
1057
1023
|
};
|
|
1058
|
-
rules[
|
|
1024
|
+
rules[_sx(scope, '.bw_form_text')] = {
|
|
1059
1025
|
'color': palette.secondary.base
|
|
1060
1026
|
};
|
|
1061
|
-
rules[
|
|
1027
|
+
rules[_sx(scope, '.bw_form_check_input:checked')] = {
|
|
1062
1028
|
'background-color': palette.primary.base,
|
|
1063
1029
|
'border-color': palette.primary.base
|
|
1064
1030
|
};
|
|
1065
|
-
rules[
|
|
1031
|
+
rules[_sx(scope, '.bw_form_check_input:focus')] = {
|
|
1066
1032
|
'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
|
|
1067
1033
|
};
|
|
1068
1034
|
// Validation states
|
|
1069
|
-
rules[
|
|
1035
|
+
rules[_sx(scope, '.bw_form_control.bw_is_valid')] = {
|
|
1070
1036
|
'border-color': palette.success.base
|
|
1071
1037
|
};
|
|
1072
|
-
rules[
|
|
1038
|
+
rules[_sx(scope, '.bw_form_control.bw_is_valid:focus')] = {
|
|
1073
1039
|
'border-color': palette.success.base,
|
|
1074
1040
|
'box-shadow': '0 0 0 0.2rem ' + palette.success.focus
|
|
1075
1041
|
};
|
|
1076
|
-
rules[
|
|
1042
|
+
rules[_sx(scope, '.bw_form_control.bw_is_invalid')] = {
|
|
1077
1043
|
'border-color': palette.danger.base
|
|
1078
1044
|
};
|
|
1079
|
-
rules[
|
|
1045
|
+
rules[_sx(scope, '.bw_form_control.bw_is_invalid:focus')] = {
|
|
1080
1046
|
'border-color': palette.danger.base,
|
|
1081
1047
|
'box-shadow': '0 0 0 0.2rem ' + palette.danger.focus
|
|
1082
1048
|
};
|
|
1083
1049
|
// Form select
|
|
1084
|
-
rules[
|
|
1050
|
+
rules[_sx(scope, '.bw_form_select')] = {
|
|
1085
1051
|
'padding': sp.input,
|
|
1086
1052
|
'border-radius': rd.input,
|
|
1087
1053
|
'color': palette.dark.base,
|
|
1088
1054
|
'background-color': palette.surface || '#fff',
|
|
1089
1055
|
'border-color': palette.light.border
|
|
1090
1056
|
};
|
|
1091
|
-
rules[
|
|
1057
|
+
rules[_sx(scope, '.bw_form_select:focus')] = {
|
|
1092
1058
|
'border-color': palette.primary.border,
|
|
1093
1059
|
'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
|
|
1094
1060
|
};
|
|
1095
1061
|
return rules;
|
|
1096
1062
|
}
|
|
1097
|
-
function generateNavigation(scope, palette) {
|
|
1063
|
+
function generateNavigation(scope, palette, layout) {
|
|
1098
1064
|
var rules = {};
|
|
1099
|
-
rules[
|
|
1100
|
-
'background-color': palette.
|
|
1065
|
+
rules[_sx(scope, '.bw_navbar')] = {
|
|
1066
|
+
'background-color': palette.surfaceAlt,
|
|
1101
1067
|
'border-bottom-color': palette.light.border
|
|
1102
1068
|
};
|
|
1103
|
-
rules[
|
|
1069
|
+
rules[_sx(scope, '.bw_navbar_brand')] = {
|
|
1104
1070
|
'color': palette.dark.base
|
|
1105
1071
|
};
|
|
1106
|
-
rules[
|
|
1107
|
-
'color': palette.secondary.base
|
|
1072
|
+
rules[_sx(scope, '.bw_navbar_nav .bw_nav_link')] = {
|
|
1073
|
+
'color': palette.secondary.base,
|
|
1074
|
+
'border-radius': layout.radius.btn
|
|
1108
1075
|
};
|
|
1109
|
-
rules[
|
|
1110
|
-
'color': palette.dark.base
|
|
1076
|
+
rules[_sx(scope, '.bw_navbar_nav .bw_nav_link:hover')] = {
|
|
1077
|
+
'color': palette.dark.base,
|
|
1078
|
+
'background-color': palette.surfaceAlt
|
|
1111
1079
|
};
|
|
1112
|
-
rules[
|
|
1080
|
+
rules[_sx(scope, '.bw_navbar_nav .bw_nav_link.active')] = {
|
|
1113
1081
|
'color': palette.primary.base,
|
|
1114
|
-
'background-color': palette.primary.focus
|
|
1082
|
+
'background-color': palette.primary.focus,
|
|
1083
|
+
'font-weight': '600'
|
|
1115
1084
|
};
|
|
1116
|
-
rules[
|
|
1085
|
+
rules[_sx(scope, '.bw_navbar_dark')] = {
|
|
1117
1086
|
'background-color': palette.dark.base,
|
|
1118
1087
|
'border-bottom-color': palette.dark.hover
|
|
1119
1088
|
};
|
|
1120
|
-
rules[
|
|
1089
|
+
rules[_sx(scope, '.bw_navbar_dark .bw_navbar_brand')] = {
|
|
1121
1090
|
'color': palette.light.base
|
|
1122
1091
|
};
|
|
1123
|
-
rules[
|
|
1124
|
-
'color':
|
|
1092
|
+
rules[_sx(scope, '.bw_navbar_dark .bw_nav_link')] = {
|
|
1093
|
+
'color': palette.light.border
|
|
1125
1094
|
};
|
|
1126
|
-
rules[
|
|
1127
|
-
'color':
|
|
1095
|
+
rules[_sx(scope, '.bw_navbar_dark .bw_nav_link:hover')] = {
|
|
1096
|
+
'color': palette.light.base
|
|
1128
1097
|
};
|
|
1129
|
-
rules[
|
|
1130
|
-
'color':
|
|
1098
|
+
rules[_sx(scope, '.bw_navbar_dark .bw_nav_link.active')] = {
|
|
1099
|
+
'color': palette.light.base,
|
|
1131
1100
|
'font-weight': '600'
|
|
1132
1101
|
};
|
|
1133
|
-
rules[
|
|
1102
|
+
rules[_sx(scope, '.bw_nav_pills .bw_nav_link.active')] = {
|
|
1134
1103
|
'color': palette.primary.textOn,
|
|
1135
1104
|
'background-color': palette.primary.base
|
|
1136
1105
|
};
|
|
@@ -1139,47 +1108,57 @@
|
|
|
1139
1108
|
function generateTables(scope, palette, layout) {
|
|
1140
1109
|
var rules = {};
|
|
1141
1110
|
var sp = layout.spacing;
|
|
1142
|
-
rules[
|
|
1111
|
+
rules[_sx(scope, '.bw_table')] = {
|
|
1143
1112
|
'color': palette.dark.base,
|
|
1144
1113
|
'border-color': palette.light.border
|
|
1145
1114
|
};
|
|
1146
|
-
rules[
|
|
1115
|
+
rules[_sx(scope, '.bw_table > :not(caption) > * > *')] = {
|
|
1147
1116
|
'padding': sp.cell,
|
|
1148
1117
|
'border-bottom-color': palette.light.border
|
|
1149
1118
|
};
|
|
1150
|
-
rules[
|
|
1119
|
+
rules[_sx(scope, '.bw_table > thead > tr > *')] = {
|
|
1151
1120
|
'color': palette.secondary.base,
|
|
1152
1121
|
'border-bottom-color': palette.light.border,
|
|
1153
|
-
'background-color': palette.
|
|
1122
|
+
'background-color': palette.surfaceAlt
|
|
1154
1123
|
};
|
|
1155
|
-
rules[
|
|
1156
|
-
'background-color':
|
|
1124
|
+
rules[_sx(scope, '.bw_table_striped > tbody > tr:nth-of-type(odd) > *')] = {
|
|
1125
|
+
'background-color': palette.surfaceAlt
|
|
1157
1126
|
};
|
|
1158
|
-
rules[
|
|
1127
|
+
rules[_sx(scope, '.bw_table_hover > tbody > tr:hover > *')] = {
|
|
1159
1128
|
'background-color': palette.primary.focus
|
|
1160
1129
|
};
|
|
1161
|
-
rules[
|
|
1130
|
+
rules[_sx(scope, '.bw_table_selectable > tbody > tr')] = {
|
|
1131
|
+
'cursor': 'pointer'
|
|
1132
|
+
};
|
|
1133
|
+
rules[_sx(scope, '.bw_table > tbody > tr.bw_table_row_selected > *')] = {
|
|
1134
|
+
'background-color': palette.primary.light
|
|
1135
|
+
};
|
|
1136
|
+
rules[_sx(scope, '.bw_table_bordered')] = {
|
|
1162
1137
|
'border-color': palette.light.border
|
|
1163
1138
|
};
|
|
1164
|
-
rules[
|
|
1139
|
+
rules[_sx(scope, '.bw_table caption')] = {
|
|
1165
1140
|
'color': palette.secondary.base
|
|
1166
1141
|
};
|
|
1167
1142
|
return rules;
|
|
1168
1143
|
}
|
|
1169
|
-
function generateTabs(scope, palette) {
|
|
1170
|
-
var rules = {}
|
|
1171
|
-
|
|
1144
|
+
function generateTabs(scope, palette, layout) {
|
|
1145
|
+
var rules = {},
|
|
1146
|
+
mo = layout.motion;
|
|
1147
|
+
rules[_sx(scope, '.bw_nav_tabs')] = {
|
|
1172
1148
|
'border-bottom-color': palette.light.border
|
|
1173
1149
|
};
|
|
1174
|
-
rules[
|
|
1175
|
-
'color': palette.secondary.base
|
|
1150
|
+
rules[_sx(scope, '.bw_nav_link')] = {
|
|
1151
|
+
'color': palette.secondary.base,
|
|
1152
|
+
'transition': 'color ' + mo.fast + ' ' + mo.easing + ', border-color ' + mo.fast + ' ' + mo.easing + ', background-color ' + mo.fast + ' ' + mo.easing
|
|
1176
1153
|
};
|
|
1177
|
-
rules[
|
|
1154
|
+
rules[_sx(scope, '.bw_nav_tabs .bw_nav_link:hover')] = {
|
|
1178
1155
|
'color': palette.dark.base,
|
|
1156
|
+
'background-color': palette.surfaceAlt,
|
|
1179
1157
|
'border-bottom-color': palette.light.border
|
|
1180
1158
|
};
|
|
1181
|
-
rules[
|
|
1159
|
+
rules[_sx(scope, '.bw_nav_tabs .bw_nav_link.active')] = {
|
|
1182
1160
|
'color': palette.primary.base,
|
|
1161
|
+
'background-color': palette.primary.focus,
|
|
1183
1162
|
'border-bottom': '2px solid ' + palette.primary.base
|
|
1184
1163
|
};
|
|
1185
1164
|
return rules;
|
|
@@ -1187,49 +1166,62 @@
|
|
|
1187
1166
|
function generateListGroups(scope, palette, layout) {
|
|
1188
1167
|
var rules = {};
|
|
1189
1168
|
var sp = layout.spacing;
|
|
1190
|
-
|
|
1169
|
+
var mo = layout.motion;
|
|
1170
|
+
rules[_sx(scope, '.bw_list_group_item')] = {
|
|
1191
1171
|
'padding': sp.cell,
|
|
1192
1172
|
'color': palette.dark.base,
|
|
1193
1173
|
'background-color': palette.surface || '#fff',
|
|
1194
|
-
'border-color': palette.light.border
|
|
1174
|
+
'border-color': palette.light.border,
|
|
1175
|
+
'transition': 'color ' + mo.fast + ' ' + mo.easing + ', background-color ' + mo.fast + ' ' + mo.easing
|
|
1195
1176
|
};
|
|
1196
|
-
rules[
|
|
1197
|
-
'background-color': palette.
|
|
1177
|
+
rules[_sx(scope, 'a.bw_list_group_item:hover')] = {
|
|
1178
|
+
'background-color': palette.surfaceAlt,
|
|
1198
1179
|
'color': palette.dark.hover
|
|
1199
1180
|
};
|
|
1200
|
-
rules[
|
|
1181
|
+
rules[_sx(scope, '.bw_list_group_item.active')] = {
|
|
1201
1182
|
'color': palette.primary.textOn,
|
|
1202
1183
|
'background-color': palette.primary.base,
|
|
1203
1184
|
'border-color': palette.primary.base
|
|
1204
1185
|
};
|
|
1205
|
-
rules[
|
|
1186
|
+
rules[_sx(scope, '.bw_list_group_item.disabled')] = {
|
|
1206
1187
|
'color': palette.secondary.base,
|
|
1207
1188
|
'background-color': palette.surface || '#fff'
|
|
1208
1189
|
};
|
|
1209
1190
|
return rules;
|
|
1210
1191
|
}
|
|
1211
|
-
function generatePagination(scope, palette) {
|
|
1212
|
-
var rules = {}
|
|
1213
|
-
|
|
1192
|
+
function generatePagination(scope, palette, layout) {
|
|
1193
|
+
var rules = {},
|
|
1194
|
+
mo = layout.motion,
|
|
1195
|
+
rd = layout.radius;
|
|
1196
|
+
rules[_sx(scope, '.bw_page_item:first-child .bw_page_link')] = {
|
|
1197
|
+
'border-top-left-radius': rd.btn,
|
|
1198
|
+
'border-bottom-left-radius': rd.btn
|
|
1199
|
+
};
|
|
1200
|
+
rules[_sx(scope, '.bw_page_item:last-child .bw_page_link')] = {
|
|
1201
|
+
'border-top-right-radius': rd.btn,
|
|
1202
|
+
'border-bottom-right-radius': rd.btn
|
|
1203
|
+
};
|
|
1204
|
+
rules[_sx(scope, '.bw_page_link')] = {
|
|
1214
1205
|
'color': palette.primary.base,
|
|
1215
1206
|
'background-color': palette.surface || '#fff',
|
|
1216
|
-
'border-color': palette.light.border
|
|
1207
|
+
'border-color': palette.light.border,
|
|
1208
|
+
'transition': 'color ' + mo.fast + ' ' + mo.easing + ', background-color ' + mo.fast + ' ' + mo.easing
|
|
1217
1209
|
};
|
|
1218
|
-
rules[
|
|
1210
|
+
rules[_sx(scope, '.bw_page_link:hover')] = {
|
|
1219
1211
|
'color': palette.primary.hover,
|
|
1220
|
-
'background-color': palette.
|
|
1212
|
+
'background-color': palette.surfaceAlt,
|
|
1221
1213
|
'border-color': palette.light.border
|
|
1222
1214
|
};
|
|
1223
|
-
rules[
|
|
1215
|
+
rules[_sx(scope, '.bw_page_link:focus')] = {
|
|
1224
1216
|
'outline': '2px solid ' + palette.primary.base,
|
|
1225
1217
|
'outline-offset': '-2px'
|
|
1226
1218
|
};
|
|
1227
|
-
rules[
|
|
1219
|
+
rules[_sx(scope, '.bw_page_item.bw_active .bw_page_link')] = {
|
|
1228
1220
|
'color': palette.primary.textOn,
|
|
1229
1221
|
'background-color': palette.primary.base,
|
|
1230
1222
|
'border-color': palette.primary.base
|
|
1231
1223
|
};
|
|
1232
|
-
rules[
|
|
1224
|
+
rules[_sx(scope, '.bw_page_item.bw_disabled .bw_page_link')] = {
|
|
1233
1225
|
'color': palette.secondary.base,
|
|
1234
1226
|
'background-color': palette.surface || '#fff',
|
|
1235
1227
|
'border-color': palette.light.border
|
|
@@ -1238,12 +1230,12 @@
|
|
|
1238
1230
|
}
|
|
1239
1231
|
function generateProgress(scope, palette) {
|
|
1240
1232
|
var rules = {};
|
|
1241
|
-
rules[
|
|
1242
|
-
'background-color': palette.
|
|
1233
|
+
rules[_sx(scope, '.bw_progress')] = {
|
|
1234
|
+
'background-color': palette.surfaceAlt,
|
|
1243
1235
|
'box-shadow': 'inset 0 1px 2px rgba(0,0,0,.1)'
|
|
1244
1236
|
};
|
|
1245
|
-
rules[
|
|
1246
|
-
'color':
|
|
1237
|
+
rules[_sx(scope, '.bw_progress_bar')] = {
|
|
1238
|
+
'color': palette.primary.textOn,
|
|
1247
1239
|
'background-color': palette.primary.base,
|
|
1248
1240
|
'box-shadow': 'inset 0 -1px 0 rgba(0,0,0,.15)'
|
|
1249
1241
|
};
|
|
@@ -1262,25 +1254,31 @@
|
|
|
1262
1254
|
'color': palette.dark.base,
|
|
1263
1255
|
'background-color': bg
|
|
1264
1256
|
};
|
|
1265
|
-
rules[
|
|
1266
|
-
// Also apply to the scope element itself so themes work on any container, not just body
|
|
1267
|
-
if (scope) {
|
|
1268
|
-
rules['.' + scope] = baseReset;
|
|
1269
|
-
}
|
|
1257
|
+
rules[_sx(scope, 'body')] = baseReset;
|
|
1270
1258
|
return rules;
|
|
1271
1259
|
}
|
|
1272
|
-
function generateBreadcrumbThemed(scope, palette) {
|
|
1273
|
-
var rules = {}
|
|
1274
|
-
|
|
1260
|
+
function generateBreadcrumbThemed(scope, palette, layout) {
|
|
1261
|
+
var rules = {},
|
|
1262
|
+
mo = layout.motion;
|
|
1263
|
+
rules[_sx(scope, '.bw_breadcrumb')] = {
|
|
1264
|
+
'background-color': palette.surfaceAlt,
|
|
1265
|
+
'padding': '0.625rem 1rem',
|
|
1266
|
+
'border-radius': layout.radius.btn
|
|
1267
|
+
};
|
|
1268
|
+
rules[_sx(scope, '.bw_breadcrumb_item + .bw_breadcrumb_item::before')] = {
|
|
1275
1269
|
'color': palette.secondary.base
|
|
1276
1270
|
};
|
|
1277
|
-
rules[
|
|
1278
|
-
'color': palette.
|
|
1271
|
+
rules[_sx(scope, '.bw_breadcrumb_item a')] = {
|
|
1272
|
+
'color': palette.primary.base,
|
|
1273
|
+
'transition': 'color ' + mo.fast + ' ' + mo.easing
|
|
1279
1274
|
};
|
|
1280
|
-
rules[
|
|
1275
|
+
rules[_sx(scope, '.bw_breadcrumb_item a:hover')] = {
|
|
1281
1276
|
'color': palette.primary.hover,
|
|
1282
1277
|
'text-decoration': 'underline'
|
|
1283
1278
|
};
|
|
1279
|
+
rules[_sx(scope, '.bw_breadcrumb_item.active')] = {
|
|
1280
|
+
'color': palette.dark.base
|
|
1281
|
+
};
|
|
1284
1282
|
return rules;
|
|
1285
1283
|
}
|
|
1286
1284
|
|
|
@@ -1288,240 +1286,273 @@
|
|
|
1288
1286
|
|
|
1289
1287
|
function generateCloseButtonThemed(scope, palette) {
|
|
1290
1288
|
var rules = {};
|
|
1291
|
-
rules[
|
|
1289
|
+
rules[_sx(scope, '.bw_close')] = {
|
|
1292
1290
|
'color': palette.dark.base,
|
|
1293
1291
|
'opacity': '0.5'
|
|
1294
1292
|
};
|
|
1295
|
-
rules[
|
|
1293
|
+
rules[_sx(scope, '.bw_close:focus')] = {
|
|
1296
1294
|
'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
|
|
1297
1295
|
};
|
|
1298
1296
|
return rules;
|
|
1299
1297
|
}
|
|
1300
1298
|
function generateSectionsThemed(scope, palette) {
|
|
1301
1299
|
var rules = {};
|
|
1302
|
-
rules[
|
|
1300
|
+
rules[_sx(scope, '.bw_section_subtitle')] = {
|
|
1303
1301
|
'color': palette.secondary.base
|
|
1304
1302
|
};
|
|
1305
|
-
rules[
|
|
1303
|
+
rules[_sx(scope, '.bw_feature_description')] = {
|
|
1306
1304
|
'color': palette.secondary.base
|
|
1307
1305
|
};
|
|
1308
|
-
rules[
|
|
1306
|
+
rules[_sx(scope, '.bw_cta_description')] = {
|
|
1309
1307
|
'color': palette.secondary.base
|
|
1310
1308
|
};
|
|
1311
1309
|
return rules;
|
|
1312
1310
|
}
|
|
1313
|
-
function generateAccordionThemed(scope, palette) {
|
|
1311
|
+
function generateAccordionThemed(scope, palette, layout) {
|
|
1314
1312
|
var rules = {};
|
|
1315
|
-
|
|
1313
|
+
var rd = layout ? layout.radius : {
|
|
1314
|
+
card: '8px'
|
|
1315
|
+
};
|
|
1316
|
+
rules[_sx(scope, '.bw_accordion_item')] = {
|
|
1316
1317
|
'background-color': palette.surface || '#fff',
|
|
1317
1318
|
'border-color': palette.light.border
|
|
1318
1319
|
};
|
|
1319
|
-
rules[
|
|
1320
|
+
rules[_sx(scope, '.bw_accordion_item:first-child')] = {
|
|
1321
|
+
'border-top-left-radius': rd.card,
|
|
1322
|
+
'border-top-right-radius': rd.card
|
|
1323
|
+
};
|
|
1324
|
+
rules[_sx(scope, '.bw_accordion_item:last-child')] = {
|
|
1325
|
+
'border-bottom-left-radius': rd.card,
|
|
1326
|
+
'border-bottom-right-radius': rd.card
|
|
1327
|
+
};
|
|
1328
|
+
rules[_sx(scope, '.bw_accordion_button')] = {
|
|
1320
1329
|
'color': palette.dark.base
|
|
1321
1330
|
};
|
|
1322
|
-
rules[
|
|
1331
|
+
rules[_sx(scope, '.bw_accordion_button:not(.bw_collapsed)')] = {
|
|
1323
1332
|
'color': palette.primary.darkText,
|
|
1324
|
-
'background-color': palette.primary.light
|
|
1333
|
+
'background-color': palette.primary.light,
|
|
1334
|
+
'border-left': '3px solid ' + palette.primary.base
|
|
1325
1335
|
};
|
|
1326
|
-
rules[
|
|
1327
|
-
'background-color': palette.
|
|
1336
|
+
rules[_sx(scope, '.bw_accordion_button:hover')] = {
|
|
1337
|
+
'background-color': palette.surfaceAlt
|
|
1328
1338
|
};
|
|
1329
|
-
rules[
|
|
1330
|
-
'background-color': palette.primary.
|
|
1339
|
+
rules[_sx(scope, '.bw_accordion_button:not(.bw_collapsed):hover')] = {
|
|
1340
|
+
'background-color': palette.primary.base,
|
|
1341
|
+
'color': palette.primary.textOn
|
|
1331
1342
|
};
|
|
1332
|
-
rules[
|
|
1343
|
+
rules[_sx(scope, '.bw_accordion_button:focus-visible')] = {
|
|
1333
1344
|
'box-shadow': '0 0 0 0.2rem ' + palette.primary.focus
|
|
1334
1345
|
};
|
|
1335
|
-
rules[
|
|
1336
|
-
'border-top': '1px solid ' + palette.light.border
|
|
1346
|
+
rules[_sx(scope, '.bw_accordion_body')] = {
|
|
1347
|
+
'border-top': '1px solid ' + palette.light.border,
|
|
1348
|
+
'background-color': palette.surfaceAlt
|
|
1337
1349
|
};
|
|
1338
1350
|
return rules;
|
|
1339
1351
|
}
|
|
1340
1352
|
function generateCarouselThemed(scope, palette) {
|
|
1341
1353
|
var rules = {};
|
|
1342
|
-
rules[
|
|
1343
|
-
'background-color': palette.
|
|
1354
|
+
rules[_sx(scope, '.bw_carousel')] = {
|
|
1355
|
+
'background-color': palette.surfaceAlt
|
|
1344
1356
|
};
|
|
1345
|
-
rules[
|
|
1357
|
+
rules[_sx(scope, '.bw_carousel_indicator.active')] = {
|
|
1346
1358
|
'background-color': palette.primary.base
|
|
1347
1359
|
};
|
|
1348
|
-
rules[
|
|
1349
|
-
'background-color':
|
|
1350
|
-
'color':
|
|
1360
|
+
rules[_sx(scope, '.bw_carousel_control')] = {
|
|
1361
|
+
'background-color': palette.dark.base,
|
|
1362
|
+
'color': palette.dark.textOn
|
|
1351
1363
|
};
|
|
1352
|
-
rules[
|
|
1353
|
-
'background-color':
|
|
1364
|
+
rules[_sx(scope, '.bw_carousel_control:hover')] = {
|
|
1365
|
+
'background-color': palette.dark.hover
|
|
1354
1366
|
};
|
|
1355
|
-
rules[
|
|
1356
|
-
'background': 'linear-gradient(transparent,
|
|
1357
|
-
'color':
|
|
1367
|
+
rules[_sx(scope, '.bw_carousel_caption')] = {
|
|
1368
|
+
'background': 'linear-gradient(transparent, ' + palette.dark.base + ')',
|
|
1369
|
+
'color': palette.dark.textOn
|
|
1358
1370
|
};
|
|
1359
1371
|
return rules;
|
|
1360
1372
|
}
|
|
1361
1373
|
function generateModalThemed(scope, palette, layout) {
|
|
1362
1374
|
var rules = {};
|
|
1363
|
-
rules[
|
|
1375
|
+
rules[_sx(scope, '.bw_modal_content')] = {
|
|
1364
1376
|
'background-color': palette.surface || '#fff',
|
|
1365
1377
|
'border-color': palette.light.border,
|
|
1366
1378
|
'box-shadow': layout.elevation.lg
|
|
1367
1379
|
};
|
|
1368
|
-
rules[
|
|
1380
|
+
rules[_sx(scope, '.bw_modal_header')] = {
|
|
1369
1381
|
'border-bottom-color': palette.light.border
|
|
1370
1382
|
};
|
|
1371
|
-
rules[
|
|
1383
|
+
rules[_sx(scope, '.bw_modal_footer')] = {
|
|
1372
1384
|
'border-top-color': palette.light.border
|
|
1373
1385
|
};
|
|
1374
|
-
rules[
|
|
1386
|
+
rules[_sx(scope, '.bw_modal_title')] = {
|
|
1375
1387
|
'color': palette.dark.base
|
|
1376
1388
|
};
|
|
1377
1389
|
return rules;
|
|
1378
1390
|
}
|
|
1379
1391
|
function generateToastThemed(scope, palette, layout) {
|
|
1380
1392
|
var rules = {};
|
|
1381
|
-
rules[
|
|
1393
|
+
rules[_sx(scope, '.bw_toast')] = {
|
|
1382
1394
|
'background-color': palette.surface || '#fff',
|
|
1383
|
-
'border-color':
|
|
1395
|
+
'border-color': palette.light.border,
|
|
1384
1396
|
'box-shadow': layout.elevation.lg
|
|
1385
1397
|
};
|
|
1386
|
-
rules[
|
|
1387
|
-
'border-bottom-color':
|
|
1398
|
+
rules[_sx(scope, '.bw_toast_header')] = {
|
|
1399
|
+
'border-bottom-color': palette.light.border
|
|
1388
1400
|
};
|
|
1389
1401
|
// Variant toast borders handled by palette class
|
|
1390
1402
|
return rules;
|
|
1391
1403
|
}
|
|
1392
1404
|
function generateDropdownThemed(scope, palette, layout) {
|
|
1393
1405
|
var rules = {};
|
|
1394
|
-
rules[
|
|
1406
|
+
rules[_sx(scope, '.bw_dropdown_menu')] = {
|
|
1395
1407
|
'background-color': palette.surface || '#fff',
|
|
1396
1408
|
'border-color': palette.light.border,
|
|
1397
1409
|
'box-shadow': layout.elevation.md
|
|
1398
1410
|
};
|
|
1399
|
-
rules[
|
|
1400
|
-
'color': palette.dark.base
|
|
1411
|
+
rules[_sx(scope, '.bw_dropdown_item')] = {
|
|
1412
|
+
'color': palette.dark.base,
|
|
1413
|
+
'transition': 'background-color ' + layout.motion.fast + ' ' + layout.motion.easing
|
|
1401
1414
|
};
|
|
1402
|
-
rules[
|
|
1415
|
+
rules[_sx(scope, '.bw_dropdown_item:hover')] = {
|
|
1403
1416
|
'color': palette.dark.hover,
|
|
1404
|
-
'background-color': palette.
|
|
1417
|
+
'background-color': palette.surfaceAlt
|
|
1405
1418
|
};
|
|
1406
|
-
rules[
|
|
1419
|
+
rules[_sx(scope, '.bw_dropdown_item.disabled')] = {
|
|
1407
1420
|
'color': palette.secondary.base
|
|
1408
1421
|
};
|
|
1409
|
-
rules[
|
|
1422
|
+
rules[_sx(scope, '.bw_dropdown_divider')] = {
|
|
1410
1423
|
'border-top-color': palette.light.border
|
|
1411
1424
|
};
|
|
1412
1425
|
return rules;
|
|
1413
1426
|
}
|
|
1414
1427
|
function generateSwitchThemed(scope, palette) {
|
|
1415
1428
|
var rules = {};
|
|
1416
|
-
rules[
|
|
1429
|
+
rules[_sx(scope, '.bw_form_switch .bw_switch_input')] = {
|
|
1417
1430
|
'background-color': palette.secondary.base,
|
|
1418
1431
|
'border-color': palette.secondary.base
|
|
1419
1432
|
};
|
|
1420
|
-
rules[
|
|
1433
|
+
rules[_sx(scope, '.bw_form_switch .bw_switch_input:checked')] = {
|
|
1421
1434
|
'background-color': palette.primary.base,
|
|
1422
1435
|
'border-color': palette.primary.base
|
|
1423
1436
|
};
|
|
1424
|
-
rules[
|
|
1437
|
+
rules[_sx(scope, '.bw_form_switch .bw_switch_input:focus')] = {
|
|
1425
1438
|
'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
|
|
1426
1439
|
};
|
|
1427
1440
|
return rules;
|
|
1428
1441
|
}
|
|
1429
1442
|
function generateSkeletonThemed(scope, palette) {
|
|
1430
1443
|
var rules = {};
|
|
1431
|
-
rules[
|
|
1432
|
-
'background': 'linear-gradient(90deg, ' + palette.light.border + ' 25%, ' + palette.
|
|
1444
|
+
rules[_sx(scope, '.bw_skeleton')] = {
|
|
1445
|
+
'background': 'linear-gradient(90deg, ' + palette.light.border + ' 25%, ' + palette.surfaceAlt + ' 37%, ' + palette.light.border + ' 63%)'
|
|
1433
1446
|
};
|
|
1434
1447
|
return rules;
|
|
1435
1448
|
}
|
|
1436
1449
|
|
|
1437
1450
|
// generateAvatarThemed: removed — palette class on root handles variants
|
|
1438
1451
|
|
|
1439
|
-
function generateStatCardThemed(scope, palette) {
|
|
1440
|
-
var rules = {}
|
|
1452
|
+
function generateStatCardThemed(scope, palette, layout) {
|
|
1453
|
+
var rules = {},
|
|
1454
|
+
mo = layout.motion,
|
|
1455
|
+
el = layout.elevation,
|
|
1456
|
+
rd = layout.radius;
|
|
1457
|
+
rules[_sx(scope, '.bw_stat_card')] = {
|
|
1458
|
+
'background-color': palette.surface || '#fff',
|
|
1459
|
+
'color': palette.dark.base,
|
|
1460
|
+
'border': '1px solid ' + palette.light.border,
|
|
1461
|
+
'border-radius': rd.card,
|
|
1462
|
+
'box-shadow': el.sm,
|
|
1463
|
+
'transition': 'box-shadow ' + mo.fast + ' ' + mo.easing + ', transform ' + mo.fast + ' ' + mo.easing
|
|
1464
|
+
};
|
|
1465
|
+
rules[_sx(scope, '.bw_stat_card:hover')] = {
|
|
1466
|
+
'box-shadow': el.md
|
|
1467
|
+
};
|
|
1441
1468
|
// Variant border colors handled by palette class
|
|
1442
|
-
rules[
|
|
1469
|
+
rules[_sx(scope, '.bw_stat_change_up')] = {
|
|
1443
1470
|
'color': palette.success.base
|
|
1444
1471
|
};
|
|
1445
|
-
rules[
|
|
1472
|
+
rules[_sx(scope, '.bw_stat_change_down')] = {
|
|
1446
1473
|
'color': palette.danger.base
|
|
1447
1474
|
};
|
|
1448
1475
|
return rules;
|
|
1449
1476
|
}
|
|
1450
1477
|
function generateTimelineThemed(scope, palette) {
|
|
1451
1478
|
var rules = {};
|
|
1452
|
-
rules[
|
|
1479
|
+
rules[_sx(scope, '.bw_timeline::before')] = {
|
|
1453
1480
|
'background-color': palette.light.border
|
|
1454
1481
|
};
|
|
1455
1482
|
// Variant marker colors handled by palette class
|
|
1456
|
-
rules[
|
|
1483
|
+
rules[_sx(scope, '.bw_timeline_date')] = {
|
|
1457
1484
|
'color': palette.secondary.base
|
|
1458
1485
|
};
|
|
1459
1486
|
return rules;
|
|
1460
1487
|
}
|
|
1461
1488
|
function generateStepperThemed(scope, palette) {
|
|
1462
1489
|
var rules = {};
|
|
1463
|
-
rules[
|
|
1464
|
-
'background-color': palette.
|
|
1490
|
+
rules[_sx(scope, '.bw_step_indicator')] = {
|
|
1491
|
+
'background-color': palette.surfaceAlt,
|
|
1465
1492
|
'border': '2px solid ' + palette.light.border,
|
|
1466
1493
|
'color': palette.secondary.base
|
|
1467
1494
|
};
|
|
1468
|
-
rules[
|
|
1495
|
+
rules[_sx(scope, '.bw_step + .bw_step::before')] = {
|
|
1469
1496
|
'background-color': palette.light.border
|
|
1470
1497
|
};
|
|
1471
|
-
rules[
|
|
1498
|
+
rules[_sx(scope, '.bw_step_active .bw_step_indicator')] = {
|
|
1472
1499
|
'background-color': palette.primary.base,
|
|
1473
1500
|
'color': palette.primary.textOn
|
|
1474
1501
|
};
|
|
1475
|
-
rules[
|
|
1502
|
+
rules[_sx(scope, '.bw_step_active .bw_step_label')] = {
|
|
1476
1503
|
'color': palette.dark.base,
|
|
1477
1504
|
'font-weight': '600'
|
|
1478
1505
|
};
|
|
1479
|
-
rules[
|
|
1506
|
+
rules[_sx(scope, '.bw_step_completed .bw_step_indicator')] = {
|
|
1480
1507
|
'background-color': palette.primary.base,
|
|
1481
1508
|
'color': palette.primary.textOn
|
|
1482
1509
|
};
|
|
1483
|
-
rules[
|
|
1510
|
+
rules[_sx(scope, '.bw_step_completed .bw_step_label')] = {
|
|
1484
1511
|
'color': palette.primary.base
|
|
1485
1512
|
};
|
|
1486
|
-
rules[
|
|
1513
|
+
rules[_sx(scope, '.bw_step_completed + .bw_step::before')] = {
|
|
1487
1514
|
'background-color': palette.primary.base
|
|
1488
1515
|
};
|
|
1489
1516
|
return rules;
|
|
1490
1517
|
}
|
|
1491
1518
|
function generateChipInputThemed(scope, palette) {
|
|
1492
1519
|
var rules = {};
|
|
1493
|
-
rules[
|
|
1494
|
-
'border-color': palette.light.border
|
|
1520
|
+
rules[_sx(scope, '.bw_chip_input')] = {
|
|
1521
|
+
'border-color': palette.light.border,
|
|
1522
|
+
'background-color': palette.surface || '#fff',
|
|
1523
|
+
'color': palette.dark.base
|
|
1495
1524
|
};
|
|
1496
|
-
rules[
|
|
1525
|
+
rules[_sx(scope, '.bw_chip_input:focus-within')] = {
|
|
1497
1526
|
'border-color': palette.primary.base,
|
|
1498
1527
|
'box-shadow': '0 0 0 0.2rem ' + palette.primary.focus
|
|
1499
1528
|
};
|
|
1500
|
-
rules[
|
|
1501
|
-
'background-color': palette.
|
|
1529
|
+
rules[_sx(scope, '.bw_chip')] = {
|
|
1530
|
+
'background-color': palette.surfaceAlt,
|
|
1502
1531
|
'color': palette.dark.base
|
|
1503
1532
|
};
|
|
1504
|
-
rules[
|
|
1533
|
+
rules[_sx(scope, '.bw_chip_remove:hover')] = {
|
|
1505
1534
|
'color': palette.danger.base,
|
|
1506
1535
|
'background-color': palette.danger.light
|
|
1507
1536
|
};
|
|
1508
1537
|
return rules;
|
|
1509
1538
|
}
|
|
1510
|
-
function generateFileUploadThemed(scope, palette) {
|
|
1511
|
-
var rules = {}
|
|
1512
|
-
|
|
1539
|
+
function generateFileUploadThemed(scope, palette, layout) {
|
|
1540
|
+
var rules = {},
|
|
1541
|
+
mo = layout.motion;
|
|
1542
|
+
rules[_sx(scope, '.bw_file_upload')] = {
|
|
1513
1543
|
'border-color': palette.light.border,
|
|
1514
|
-
'background-color': palette.
|
|
1544
|
+
'background-color': palette.surfaceAlt,
|
|
1545
|
+
'transition': 'border-color ' + mo.fast + ' ' + mo.easing + ', background-color ' + mo.fast + ' ' + mo.easing
|
|
1515
1546
|
};
|
|
1516
|
-
rules[
|
|
1547
|
+
rules[_sx(scope, '.bw_file_upload:hover')] = {
|
|
1517
1548
|
'border-color': palette.primary.base,
|
|
1518
1549
|
'background-color': palette.primary.light
|
|
1519
1550
|
};
|
|
1520
|
-
rules[
|
|
1551
|
+
rules[_sx(scope, '.bw_file_upload:focus')] = {
|
|
1521
1552
|
'outline': '2px solid ' + palette.primary.base,
|
|
1522
1553
|
'outline-offset': '2px'
|
|
1523
1554
|
};
|
|
1524
|
-
rules[
|
|
1555
|
+
rules[_sx(scope, '.bw_file_upload.bw_file_upload_active')] = {
|
|
1525
1556
|
'border-color': palette.primary.base,
|
|
1526
1557
|
'background-color': palette.primary.light,
|
|
1527
1558
|
'border-style': 'solid'
|
|
@@ -1530,37 +1561,93 @@
|
|
|
1530
1561
|
}
|
|
1531
1562
|
function generateRangeThemed(scope, palette) {
|
|
1532
1563
|
var rules = {};
|
|
1533
|
-
rules[
|
|
1564
|
+
rules[_sx(scope, '.bw_range')] = {
|
|
1534
1565
|
'background-color': palette.light.border
|
|
1535
1566
|
};
|
|
1536
|
-
rules[
|
|
1567
|
+
rules[_sx(scope, '.bw_range::-webkit-slider-thumb')] = {
|
|
1537
1568
|
'background-color': palette.primary.base,
|
|
1538
|
-
'border-color': '#fff',
|
|
1569
|
+
'border-color': palette.surface || '#fff',
|
|
1539
1570
|
'box-shadow': '0 1px 3px rgba(0,0,0,0.2)',
|
|
1540
1571
|
'transition': 'background-color 0.15s ease-out, transform 0.15s ease-out'
|
|
1541
1572
|
};
|
|
1542
|
-
rules[
|
|
1573
|
+
rules[_sx(scope, '.bw_range::-moz-range-thumb')] = {
|
|
1543
1574
|
'background-color': palette.primary.base,
|
|
1544
|
-
'border-color': '#fff',
|
|
1575
|
+
'border-color': palette.surface || '#fff',
|
|
1545
1576
|
'box-shadow': '0 1px 3px rgba(0,0,0,0.2)'
|
|
1546
1577
|
};
|
|
1547
1578
|
return rules;
|
|
1548
1579
|
}
|
|
1549
|
-
function
|
|
1550
|
-
var rules = {}
|
|
1551
|
-
|
|
1580
|
+
function generateTooltipThemed(scope, palette, layout) {
|
|
1581
|
+
var rules = {},
|
|
1582
|
+
sp = layout.spacing,
|
|
1583
|
+
rd = layout.radius,
|
|
1584
|
+
el = layout.elevation,
|
|
1585
|
+
mo = layout.motion;
|
|
1586
|
+
rules[_sx(scope, '.bw_tooltip')] = {
|
|
1587
|
+
'background-color': palette.dark.base,
|
|
1588
|
+
'color': palette.dark.textOn,
|
|
1589
|
+
'padding': sp.input,
|
|
1590
|
+
'border-radius': rd.badge,
|
|
1591
|
+
'box-shadow': el.md,
|
|
1592
|
+
'transition': 'opacity ' + mo.fast + ' ' + mo.easing + ', transform ' + mo.fast + ' ' + mo.easing
|
|
1593
|
+
};
|
|
1594
|
+
return rules;
|
|
1595
|
+
}
|
|
1596
|
+
function generatePopoverThemed(scope, palette, layout) {
|
|
1597
|
+
var rules = {},
|
|
1598
|
+
sp = layout.spacing,
|
|
1599
|
+
rd = layout.radius,
|
|
1600
|
+
el = layout.elevation,
|
|
1601
|
+
mo = layout.motion;
|
|
1602
|
+
rules[_sx(scope, '.bw_popover')] = {
|
|
1603
|
+
'background-color': palette.surface || '#fff',
|
|
1604
|
+
'color': palette.dark.base,
|
|
1605
|
+
'border': '1px solid ' + palette.light.border,
|
|
1606
|
+
'border-radius': rd.card,
|
|
1607
|
+
'box-shadow': el.lg,
|
|
1608
|
+
'transition': 'opacity ' + mo.fast + ' ' + mo.easing + ', transform ' + mo.fast + ' ' + mo.easing
|
|
1609
|
+
};
|
|
1610
|
+
rules[_sx(scope, '.bw_popover_header')] = {
|
|
1611
|
+
'background-color': palette.surfaceAlt,
|
|
1612
|
+
'border-bottom': '1px solid ' + palette.light.border,
|
|
1613
|
+
'padding': sp.input
|
|
1614
|
+
};
|
|
1615
|
+
rules[_sx(scope, '.bw_popover_body')] = {
|
|
1616
|
+
'padding': sp.card
|
|
1617
|
+
};
|
|
1618
|
+
return rules;
|
|
1619
|
+
}
|
|
1620
|
+
function generateSearchThemed(scope, palette, layout) {
|
|
1621
|
+
var rules = {},
|
|
1622
|
+
mo = layout.motion;
|
|
1623
|
+
rules[_sx(scope, '.bw_search_input')] = {
|
|
1624
|
+
'background-color': palette.surface || '#fff',
|
|
1625
|
+
'color': palette.dark.base
|
|
1626
|
+
};
|
|
1627
|
+
rules[_sx(scope, '.bw_search_clear')] = {
|
|
1628
|
+
'transition': 'color ' + mo.fast + ' ' + mo.easing + ', background-color ' + mo.fast + ' ' + mo.easing
|
|
1629
|
+
};
|
|
1630
|
+
rules[_sx(scope, '.bw_search_clear:hover')] = {
|
|
1552
1631
|
'color': palette.dark.base
|
|
1553
1632
|
};
|
|
1554
1633
|
return rules;
|
|
1555
1634
|
}
|
|
1556
|
-
function generateCodeDemoThemed(scope, palette) {
|
|
1635
|
+
function generateCodeDemoThemed(scope, palette, layout) {
|
|
1557
1636
|
var rules = {};
|
|
1558
|
-
|
|
1637
|
+
var rd = layout ? layout.radius : {
|
|
1638
|
+
card: '0.375rem'
|
|
1639
|
+
};
|
|
1640
|
+
rules[_sx(scope, '.bw_code_demo')] = {
|
|
1641
|
+
'background-color': palette.surface || '#fff',
|
|
1642
|
+
'color': palette.dark.base,
|
|
1643
|
+
'border-radius': rd.card
|
|
1644
|
+
};
|
|
1645
|
+
rules[_sx(scope, '.bw_code_copy_btn_copied')] = {
|
|
1559
1646
|
'background': palette.success.base,
|
|
1560
1647
|
'color': palette.success.textOn,
|
|
1561
1648
|
'border-color': palette.success.base
|
|
1562
1649
|
};
|
|
1563
|
-
rules[
|
|
1650
|
+
rules[_sx(scope, '.bw_copy_btn:hover')] = {
|
|
1564
1651
|
'background': 'rgba(255,255,255,0.2)',
|
|
1565
1652
|
'color': '#fff'
|
|
1566
1653
|
};
|
|
@@ -1569,7 +1656,7 @@
|
|
|
1569
1656
|
function generateNavPillsThemed(scope, palette, layout) {
|
|
1570
1657
|
var rules = {};
|
|
1571
1658
|
var rd = layout.radius;
|
|
1572
|
-
rules[
|
|
1659
|
+
rules[_sx(scope, '.bw_nav_pills .bw_nav_link')] = {
|
|
1573
1660
|
'border-radius': rd.btn
|
|
1574
1661
|
};
|
|
1575
1662
|
return rules;
|
|
@@ -1597,21 +1684,21 @@
|
|
|
1597
1684
|
var s = palette[k];
|
|
1598
1685
|
|
|
1599
1686
|
// --- Root palette class: sets default bg/color/border ---
|
|
1600
|
-
rules[
|
|
1687
|
+
rules[_sx(scope, '.bw_' + k)] = {
|
|
1601
1688
|
'background-color': s.base,
|
|
1602
1689
|
'color': s.textOn,
|
|
1603
1690
|
'border-color': s.base
|
|
1604
1691
|
};
|
|
1605
1692
|
|
|
1606
1693
|
// --- Pseudo-states (shared across all components) ---
|
|
1607
|
-
rules[
|
|
1694
|
+
rules[_sx(scope, '.bw_' + k + ':hover')] = {
|
|
1608
1695
|
'background-color': s.hover,
|
|
1609
1696
|
'border-color': s.active
|
|
1610
1697
|
};
|
|
1611
|
-
rules[
|
|
1698
|
+
rules[_sx(scope, '.bw_' + k + ':active')] = {
|
|
1612
1699
|
'background-color': s.active
|
|
1613
1700
|
};
|
|
1614
|
-
rules[
|
|
1701
|
+
rules[_sx(scope, '.bw_' + k + ':focus-visible')] = {
|
|
1615
1702
|
'box-shadow': '0 0 0 3px ' + s.focus,
|
|
1616
1703
|
'outline': 'none'
|
|
1617
1704
|
};
|
|
@@ -1619,71 +1706,110 @@
|
|
|
1619
1706
|
// --- Component-specific overrides ---
|
|
1620
1707
|
|
|
1621
1708
|
// Alerts: light bg, dark text, subtle border
|
|
1622
|
-
rules[
|
|
1709
|
+
rules[_sx(scope, '.bw_alert.bw_' + k)] = {
|
|
1623
1710
|
'background-color': s.light,
|
|
1624
1711
|
'color': s.darkText,
|
|
1625
1712
|
'border-color': s.border
|
|
1626
1713
|
};
|
|
1627
1714
|
|
|
1628
1715
|
// Toast: inherit bg, left border accent
|
|
1629
|
-
rules[
|
|
1716
|
+
rules[_sx(scope, '.bw_toast.bw_' + k)] = {
|
|
1630
1717
|
'background-color': 'inherit',
|
|
1631
1718
|
'color': 'inherit',
|
|
1632
1719
|
'border-left': '4px solid ' + s.base
|
|
1633
1720
|
};
|
|
1634
1721
|
|
|
1635
1722
|
// Stat card: inherit bg, left border accent
|
|
1636
|
-
rules[
|
|
1723
|
+
rules[_sx(scope, '.bw_stat_card.bw_' + k)] = {
|
|
1637
1724
|
'background-color': 'inherit',
|
|
1638
1725
|
'color': 'inherit',
|
|
1639
1726
|
'border-left-color': s.base
|
|
1640
1727
|
};
|
|
1641
1728
|
|
|
1642
1729
|
// Card accent: left border accent, inherit bg
|
|
1643
|
-
rules[
|
|
1730
|
+
rules[_sx(scope, '.bw_card.bw_' + k)] = {
|
|
1644
1731
|
'background-color': 'inherit',
|
|
1645
1732
|
'color': 'inherit',
|
|
1646
1733
|
'border-left': '4px solid ' + s.base
|
|
1647
1734
|
};
|
|
1648
1735
|
|
|
1649
1736
|
// Timeline marker: colored dot
|
|
1650
|
-
rules[
|
|
1737
|
+
rules[_sx(scope, '.bw_timeline_marker.bw_' + k)] = {
|
|
1651
1738
|
'box-shadow': '0 0 0 2px ' + s.base
|
|
1652
1739
|
};
|
|
1653
1740
|
|
|
1654
|
-
// Spinner:
|
|
1655
|
-
|
|
1741
|
+
// Spinner: set color, re-apply border pattern so the root palette class
|
|
1742
|
+
// border-color doesn't fill in the transparent gap that makes it spin.
|
|
1743
|
+
// Also neutralize hover/active which would override border-right-color.
|
|
1744
|
+
rules[_sx(scope, '.bw_spinner_border.bw_' + k)] = {
|
|
1656
1745
|
'background-color': 'transparent',
|
|
1657
1746
|
'color': s.base,
|
|
1658
|
-
'border-color':
|
|
1747
|
+
'border-color': s.base,
|
|
1748
|
+
'border-right-color': 'transparent'
|
|
1749
|
+
};
|
|
1750
|
+
rules[_sx(scope, '.bw_spinner_border.bw_' + k + ':hover')] = {
|
|
1751
|
+
'background-color': 'transparent',
|
|
1752
|
+
'border-color': s.base,
|
|
1753
|
+
'border-right-color': 'transparent'
|
|
1754
|
+
};
|
|
1755
|
+
rules[_sx(scope, '.bw_spinner_grow.bw_' + k)] = {
|
|
1756
|
+
'background-color': s.base,
|
|
1757
|
+
'color': s.base
|
|
1659
1758
|
};
|
|
1660
1759
|
|
|
1661
1760
|
// Outline button: transparent bg, colored border+text, solid on hover
|
|
1662
|
-
rules[
|
|
1761
|
+
rules[_sx(scope, '.bw_btn_outline.bw_' + k)] = {
|
|
1663
1762
|
'background-color': 'transparent',
|
|
1664
1763
|
'color': s.base,
|
|
1665
1764
|
'border-color': s.base
|
|
1666
1765
|
};
|
|
1667
|
-
rules[
|
|
1766
|
+
rules[_sx(scope, '.bw_btn_outline.bw_' + k + ':hover')] = {
|
|
1668
1767
|
'background-color': s.base,
|
|
1669
1768
|
'color': s.textOn
|
|
1670
1769
|
};
|
|
1671
1770
|
|
|
1672
1771
|
// Hero: gradient background
|
|
1673
|
-
rules[
|
|
1772
|
+
rules[_sx(scope, '.bw_hero.bw_' + k)] = {
|
|
1674
1773
|
'background': 'linear-gradient(135deg, ' + s.base + ' 0%, ' + s.hover + ' 100%)',
|
|
1675
1774
|
'color': s.textOn
|
|
1676
1775
|
};
|
|
1677
1776
|
|
|
1678
|
-
// Progress bar:
|
|
1679
|
-
rules[
|
|
1680
|
-
'color':
|
|
1777
|
+
// Progress bar: contrasting text on colored bg
|
|
1778
|
+
rules[_sx(scope, '.bw_progress_bar.bw_' + k)] = {
|
|
1779
|
+
'color': s.textOn
|
|
1780
|
+
};
|
|
1781
|
+
|
|
1782
|
+
// Background utility: .bw_bg_primary, .bw_bg_secondary, etc.
|
|
1783
|
+
rules[_sx(scope, '.bw_bg_' + k)] = {
|
|
1784
|
+
'background-color': s.base,
|
|
1785
|
+
'color': s.textOn
|
|
1786
|
+
};
|
|
1787
|
+
|
|
1788
|
+
// Text color utility: .bw_text_primary, .bw_text_secondary, etc.
|
|
1789
|
+
rules[_sx(scope, '.bw_text_' + k)] = {
|
|
1790
|
+
'color': s.base
|
|
1681
1791
|
};
|
|
1682
1792
|
});
|
|
1683
1793
|
|
|
1684
|
-
// Text muted
|
|
1685
|
-
rules[
|
|
1686
|
-
'color':
|
|
1794
|
+
// Text muted — always a neutral gray, never a brand color
|
|
1795
|
+
rules[_sx(scope, '.bw_text_muted')] = {
|
|
1796
|
+
'color': '#6c757d'
|
|
1797
|
+
};
|
|
1798
|
+
|
|
1799
|
+
// Common bg/text utilities that aren't per-variant
|
|
1800
|
+
rules[_sx(scope, '.bw_bg_dark')] = {
|
|
1801
|
+
'background-color': '#212529',
|
|
1802
|
+
'color': '#f8f9fa'
|
|
1803
|
+
};
|
|
1804
|
+
rules[_sx(scope, '.bw_bg_light')] = {
|
|
1805
|
+
'background-color': '#f8f9fa',
|
|
1806
|
+
'color': '#212529'
|
|
1807
|
+
};
|
|
1808
|
+
rules[_sx(scope, '.bw_text_light')] = {
|
|
1809
|
+
'color': '#f8f9fa'
|
|
1810
|
+
};
|
|
1811
|
+
rules[_sx(scope, '.bw_text_dark')] = {
|
|
1812
|
+
'color': '#212529'
|
|
1687
1813
|
};
|
|
1688
1814
|
return rules;
|
|
1689
1815
|
}
|
|
@@ -1698,7 +1824,7 @@
|
|
|
1698
1824
|
* @returns {Object} CSS rules object
|
|
1699
1825
|
*/
|
|
1700
1826
|
function generateThemedCSS(scopeName, palette, layout) {
|
|
1701
|
-
return Object.assign({}, generateResetThemed(scopeName, palette), generateTypographyThemed(scopeName, palette, layout), generateButtons(scopeName, palette, layout), generateAlerts(scopeName, palette, layout), generateCards(scopeName, palette, layout), generateForms(scopeName, palette, layout), generateNavigation(scopeName, palette), generateTables(scopeName, palette, layout), generateTabs(scopeName, palette), generateListGroups(scopeName, palette, layout), generatePagination(scopeName, palette), generateProgress(scopeName, palette), generateBreadcrumbThemed(scopeName, palette), generateCloseButtonThemed(scopeName, palette), generateSectionsThemed(scopeName, palette), generateAccordionThemed(scopeName, palette), generateCarouselThemed(scopeName, palette), generateModalThemed(scopeName, palette, layout), generateToastThemed(scopeName, palette, layout), generateDropdownThemed(scopeName, palette, layout), generateSwitchThemed(scopeName, palette), generateSkeletonThemed(scopeName, palette), generateStatCardThemed(scopeName, palette), generateTimelineThemed(scopeName, palette), generateStepperThemed(scopeName, palette), generateChipInputThemed(scopeName, palette), generateFileUploadThemed(scopeName, palette), generateRangeThemed(scopeName, palette), generateSearchThemed(scopeName, palette), generateCodeDemoThemed(scopeName, palette), generateNavPillsThemed(scopeName, palette, layout), generatePaletteClasses(scopeName, palette));
|
|
1827
|
+
return Object.assign({}, generateResetThemed(scopeName, palette), generateTypographyThemed(scopeName, palette, layout), generateButtons(scopeName, palette, layout), generateAlerts(scopeName, palette, layout), generateCards(scopeName, palette, layout), generateForms(scopeName, palette, layout), generateNavigation(scopeName, palette, layout), generateTables(scopeName, palette, layout), generateTabs(scopeName, palette, layout), generateListGroups(scopeName, palette, layout), generatePagination(scopeName, palette, layout), generateProgress(scopeName, palette), generateBreadcrumbThemed(scopeName, palette, layout), generateCloseButtonThemed(scopeName, palette), generateSectionsThemed(scopeName, palette), generateAccordionThemed(scopeName, palette, layout), generateCarouselThemed(scopeName, palette), generateModalThemed(scopeName, palette, layout), generateToastThemed(scopeName, palette, layout), generateDropdownThemed(scopeName, palette, layout), generateSwitchThemed(scopeName, palette), generateSkeletonThemed(scopeName, palette), generateStatCardThemed(scopeName, palette, layout), generateTimelineThemed(scopeName, palette), generateStepperThemed(scopeName, palette), generateChipInputThemed(scopeName, palette), generateFileUploadThemed(scopeName, palette, layout), generateRangeThemed(scopeName, palette), generateSearchThemed(scopeName, palette, layout), generateTooltipThemed(scopeName, palette, layout), generatePopoverThemed(scopeName, palette, layout), generateCodeDemoThemed(scopeName, palette, layout), generateNavPillsThemed(scopeName, palette, layout), generatePaletteClasses(scopeName, palette));
|
|
1702
1828
|
}
|
|
1703
1829
|
|
|
1704
1830
|
// =========================================================================
|
|
@@ -2193,6 +2319,12 @@
|
|
|
2193
2319
|
'border-width': '1px',
|
|
2194
2320
|
'border-style': 'solid'
|
|
2195
2321
|
},
|
|
2322
|
+
'.bw_table_selectable > tbody > tr': {
|
|
2323
|
+
'cursor': 'pointer'
|
|
2324
|
+
},
|
|
2325
|
+
'.bw_table > tbody > tr.bw_table_row_selected > *': {
|
|
2326
|
+
'background-color': 'rgba(0, 102, 102, 0.1)'
|
|
2327
|
+
},
|
|
2196
2328
|
'.bw_table_responsive': {
|
|
2197
2329
|
'overflow-x': 'auto',
|
|
2198
2330
|
'-webkit-overflow-scrolling': 'touch'
|
|
@@ -2306,6 +2438,7 @@
|
|
|
2306
2438
|
'display': 'block',
|
|
2307
2439
|
'font-size': '0.875rem',
|
|
2308
2440
|
'font-weight': '500',
|
|
2441
|
+
'padding': '0.625rem 1rem',
|
|
2309
2442
|
'text-decoration': 'none',
|
|
2310
2443
|
'cursor': 'pointer',
|
|
2311
2444
|
'border': 'none',
|
|
@@ -2408,16 +2541,15 @@
|
|
|
2408
2541
|
'padding': '0.375rem 0.75rem',
|
|
2409
2542
|
'margin-left': '-1px',
|
|
2410
2543
|
'line-height': '1.25',
|
|
2411
|
-
'text-decoration': 'none'
|
|
2544
|
+
'text-decoration': 'none',
|
|
2545
|
+
'border': '1px solid transparent',
|
|
2546
|
+
'cursor': 'pointer',
|
|
2547
|
+
'font-family': 'inherit',
|
|
2548
|
+
'font-size': 'inherit',
|
|
2549
|
+
'background': 'none'
|
|
2412
2550
|
},
|
|
2413
2551
|
'.bw_page_item:first-child .bw_page_link': {
|
|
2414
|
-
'margin-left': '0'
|
|
2415
|
-
'border-top-left-radius': '0.375rem',
|
|
2416
|
-
'border-bottom-left-radius': '0.375rem'
|
|
2417
|
-
},
|
|
2418
|
-
'.bw_page_item:last-child .bw_page_link': {
|
|
2419
|
-
'border-top-right-radius': '0.375rem',
|
|
2420
|
-
'border-bottom-right-radius': '0.375rem'
|
|
2552
|
+
'margin-left': '0'
|
|
2421
2553
|
},
|
|
2422
2554
|
'.bw_page_link:focus-visible': {
|
|
2423
2555
|
'z-index': '3',
|
|
@@ -2788,6 +2920,7 @@
|
|
|
2788
2920
|
'display': 'flex',
|
|
2789
2921
|
'align-items': 'center',
|
|
2790
2922
|
'width': '100%',
|
|
2923
|
+
'padding': '0.875rem 1.25rem',
|
|
2791
2924
|
'font-size': '1rem',
|
|
2792
2925
|
'font-weight': '500',
|
|
2793
2926
|
'text-align': 'left',
|
|
@@ -2810,20 +2943,16 @@
|
|
|
2810
2943
|
'.bw_accordion_button:not(.bw_collapsed)::after': {
|
|
2811
2944
|
'transform': 'rotate(-180deg)'
|
|
2812
2945
|
},
|
|
2946
|
+
'.bw_accordion_body': {
|
|
2947
|
+
'padding': '1rem 1.25rem'
|
|
2948
|
+
},
|
|
2813
2949
|
'.bw_accordion_collapse': {
|
|
2814
2950
|
'max-height': '0',
|
|
2815
|
-
'overflow': 'hidden'
|
|
2951
|
+
'overflow': 'hidden',
|
|
2952
|
+
'transition': 'max-height 0.3s ease'
|
|
2816
2953
|
},
|
|
2817
2954
|
'.bw_accordion_collapse.bw_collapse_show': {
|
|
2818
2955
|
'max-height': 'none'
|
|
2819
|
-
},
|
|
2820
|
-
'.bw_accordion_item:first-child': {
|
|
2821
|
-
'border-top-left-radius': '8px',
|
|
2822
|
-
'border-top-right-radius': '8px'
|
|
2823
|
-
},
|
|
2824
|
-
'.bw_accordion_item:last-child': {
|
|
2825
|
-
'border-bottom-left-radius': '8px',
|
|
2826
|
-
'border-bottom-right-radius': '8px'
|
|
2827
2956
|
}
|
|
2828
2957
|
},
|
|
2829
2958
|
// ---- Carousel ----
|
|
@@ -3191,7 +3320,11 @@
|
|
|
3191
3320
|
// ---- Stat card ----
|
|
3192
3321
|
statCard: {
|
|
3193
3322
|
'.bw_stat_card': {
|
|
3194
|
-
'
|
|
3323
|
+
'padding': '1.25rem',
|
|
3324
|
+
'border-left': '4px solid transparent',
|
|
3325
|
+
'border-radius': '0.375rem',
|
|
3326
|
+
'background-color': 'inherit',
|
|
3327
|
+
'transition': 'transform 0.15s ease'
|
|
3195
3328
|
},
|
|
3196
3329
|
'.bw_stat_card:hover': {
|
|
3197
3330
|
'transform': 'translateY(-1px)'
|
|
@@ -4209,6 +4342,52 @@
|
|
|
4209
4342
|
'margin-right': '.5rem'
|
|
4210
4343
|
};
|
|
4211
4344
|
|
|
4345
|
+
// Typography — bw_ prefixed utilities via loops
|
|
4346
|
+
var _imp = function _imp(p, v) {
|
|
4347
|
+
var o = {};
|
|
4348
|
+
o[p] = v + ' !important';
|
|
4349
|
+
return o;
|
|
4350
|
+
};
|
|
4351
|
+
[['fs', {
|
|
4352
|
+
'xs': '0.75rem',
|
|
4353
|
+
'sm': '0.875rem',
|
|
4354
|
+
'base': '1rem',
|
|
4355
|
+
'lg': '1.125rem',
|
|
4356
|
+
'xl': '1.25rem',
|
|
4357
|
+
'2xl': '1.5rem'
|
|
4358
|
+
}, 'font-size'], ['fw', {
|
|
4359
|
+
light: '300',
|
|
4360
|
+
normal: '400',
|
|
4361
|
+
medium: '500',
|
|
4362
|
+
semibold: '600',
|
|
4363
|
+
bold: '700'
|
|
4364
|
+
}, 'font-weight'], ['lh', {
|
|
4365
|
+
tight: '1.25',
|
|
4366
|
+
normal: '1.5',
|
|
4367
|
+
relaxed: '1.75'
|
|
4368
|
+
}, 'line-height']].forEach(function (d) {
|
|
4369
|
+
for (var dk in d[1]) rules['.bw_' + d[0] + '_' + dk] = _imp(d[2], d[1][dk]);
|
|
4370
|
+
});
|
|
4371
|
+
|
|
4372
|
+
// Flex utilities
|
|
4373
|
+
rules['.bw_flex'] = {
|
|
4374
|
+
'display': 'flex'
|
|
4375
|
+
};
|
|
4376
|
+
rules['.bw_flex_column'] = {
|
|
4377
|
+
'flex-direction': 'column'
|
|
4378
|
+
};
|
|
4379
|
+
rules['.bw_flex_wrap'] = {
|
|
4380
|
+
'flex-wrap': 'wrap'
|
|
4381
|
+
};
|
|
4382
|
+
rules['.bw_flex_center'] = {
|
|
4383
|
+
'display': 'flex',
|
|
4384
|
+
'align-items': 'center',
|
|
4385
|
+
'justify-content': 'center'
|
|
4386
|
+
};
|
|
4387
|
+
for (var gk in spacingValues) rules['.bw_gap_' + gk] = {
|
|
4388
|
+
'gap': spacingValues[gk] + ' !important'
|
|
4389
|
+
};
|
|
4390
|
+
|
|
4212
4391
|
// Visibility
|
|
4213
4392
|
rules['.bw_visible, .visible'] = {
|
|
4214
4393
|
'visibility': 'visible !important'
|
|
@@ -4287,6 +4466,26 @@
|
|
|
4287
4466
|
return getStructuralCSS();
|
|
4288
4467
|
}
|
|
4289
4468
|
|
|
4469
|
+
/**
|
|
4470
|
+
* Get CSS reset rules only (box-sizing, html/body font, reduced-motion).
|
|
4471
|
+
* Separate from themed/structural rules for independent injection.
|
|
4472
|
+
* @returns {Object} CSS rules object for the reset layer
|
|
4473
|
+
*/
|
|
4474
|
+
function getResetStyles() {
|
|
4475
|
+
var rules = {};
|
|
4476
|
+
Object.assign(rules, structuralRules.base);
|
|
4477
|
+
// Include reduced-motion preference
|
|
4478
|
+
rules['@media (prefers-reduced-motion: reduce)'] = {
|
|
4479
|
+
'*, *::before, *::after': {
|
|
4480
|
+
'animation-duration': '0.01ms !important',
|
|
4481
|
+
'animation-iteration-count': '1 !important',
|
|
4482
|
+
'transition-duration': '0.01ms !important',
|
|
4483
|
+
'scroll-behavior': 'auto !important'
|
|
4484
|
+
}
|
|
4485
|
+
};
|
|
4486
|
+
return rules;
|
|
4487
|
+
}
|
|
4488
|
+
|
|
4290
4489
|
// =========================================================================
|
|
4291
4490
|
// defaultStyles — backward-compatible categorized view
|
|
4292
4491
|
// =========================================================================
|
|
@@ -4321,57 +4520,40 @@
|
|
|
4321
4520
|
});
|
|
4322
4521
|
|
|
4323
4522
|
/**
|
|
4324
|
-
*
|
|
4325
|
-
*
|
|
4326
|
-
*
|
|
4327
|
-
*
|
|
4328
|
-
* @param {
|
|
4329
|
-
*
|
|
4330
|
-
* @
|
|
4331
|
-
* @returns {Object} CSS rules object scoped under .bw_theme_alt (+ optional .name)
|
|
4523
|
+
* Prefix every selector in a rules object with a scope selector.
|
|
4524
|
+
* Handles @media/@keyframes blocks and comma-separated selectors.
|
|
4525
|
+
* @param {Object} rules - CSS rules object
|
|
4526
|
+
* @param {string} prefix - Scope prefix (e.g. '#my-dashboard', '.bw_theme_alt')
|
|
4527
|
+
* @param {boolean} [compound=false] - If true, use compound selector (no space)
|
|
4528
|
+
* for the first segment: `#scope.bw_theme_alt .sel` vs `#scope .sel`
|
|
4529
|
+
* @returns {Object} New rules object with scoped selectors
|
|
4332
4530
|
*/
|
|
4333
|
-
function
|
|
4334
|
-
|
|
4335
|
-
var
|
|
4336
|
-
|
|
4337
|
-
// Re-scope every selector under .bw_theme_alt (+ optional theme name)
|
|
4338
|
-
var altPrefix = name ? '.' + name + '.bw_theme_alt' : '.bw_theme_alt';
|
|
4339
|
-
var altRules = {};
|
|
4340
|
-
for (var sel in rawRules) {
|
|
4341
|
-
if (!rawRules.hasOwnProperty(sel)) continue;
|
|
4531
|
+
function scopeRulesUnder(rules, prefix, compound) {
|
|
4532
|
+
var scoped = {};
|
|
4533
|
+
for (var sel in rules) {
|
|
4534
|
+
if (!rules.hasOwnProperty(sel)) continue;
|
|
4342
4535
|
if (sel.charAt(0) === '@') {
|
|
4343
4536
|
// @media / @keyframes — recurse into the block
|
|
4344
|
-
var innerBlock =
|
|
4345
|
-
var
|
|
4537
|
+
var innerBlock = rules[sel];
|
|
4538
|
+
var scopedInner = {};
|
|
4346
4539
|
for (var innerSel in innerBlock) {
|
|
4347
4540
|
if (!innerBlock.hasOwnProperty(innerSel)) continue;
|
|
4348
|
-
|
|
4541
|
+
scopedInner[_prefixSelector(innerSel, prefix)] = innerBlock[innerSel];
|
|
4349
4542
|
}
|
|
4350
|
-
|
|
4543
|
+
scoped[sel] = scopedInner;
|
|
4351
4544
|
} else {
|
|
4352
|
-
|
|
4353
|
-
// Handle comma-separated selectors
|
|
4354
|
-
var parts = sel.split(',');
|
|
4355
|
-
var scopedParts = [];
|
|
4356
|
-
for (var i = 0; i < parts.length; i++) {
|
|
4357
|
-
var s = parts[i].trim();
|
|
4358
|
-
// 'body' selector gets special treatment: .bw_theme_alt body
|
|
4359
|
-
if (s === 'body' || s.indexOf('body') === 0) {
|
|
4360
|
-
scopedParts.push(altPrefix + ' ' + s);
|
|
4361
|
-
} else {
|
|
4362
|
-
scopedParts.push(altPrefix + ' ' + s);
|
|
4363
|
-
}
|
|
4364
|
-
}
|
|
4365
|
-
altRules[scopedParts.join(', ')] = rawRules[sel];
|
|
4545
|
+
scoped[_prefixSelector(sel, prefix)] = rules[sel];
|
|
4366
4546
|
}
|
|
4367
4547
|
}
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4548
|
+
return scoped;
|
|
4549
|
+
}
|
|
4550
|
+
function _prefixSelector(sel, prefix) {
|
|
4551
|
+
var parts = sel.split(',');
|
|
4552
|
+
var result = [];
|
|
4553
|
+
for (var i = 0; i < parts.length; i++) {
|
|
4554
|
+
result.push(prefix + ' ' + parts[i].trim());
|
|
4555
|
+
}
|
|
4556
|
+
return result.join(', ');
|
|
4375
4557
|
}
|
|
4376
4558
|
|
|
4377
4559
|
/**
|
|
@@ -5125,7 +5307,7 @@
|
|
|
5125
5307
|
__monkey_patch_is_nodejs__: {
|
|
5126
5308
|
_value: 'ignore',
|
|
5127
5309
|
set: function set(x) {
|
|
5128
|
-
this._value =
|
|
5310
|
+
this._value = _is(x, 'boolean') ? x : 'ignore';
|
|
5129
5311
|
},
|
|
5130
5312
|
get: function get() {
|
|
5131
5313
|
return this._value;
|
|
@@ -5173,6 +5355,76 @@
|
|
|
5173
5355
|
configurable: true
|
|
5174
5356
|
});
|
|
5175
5357
|
|
|
5358
|
+
// ── Internal aliases ─────────────────────────────────────────────────────
|
|
5359
|
+
// Short names for frequently-used builtins and internal methods.
|
|
5360
|
+
// Same pattern as v1 (_to = bw.typeOf, etc.).
|
|
5361
|
+
//
|
|
5362
|
+
// Why: Terser can't shorten global property chains (console.warn,
|
|
5363
|
+
// Object.prototype.hasOwnProperty, Array.isArray, document.createElement)
|
|
5364
|
+
// because it can't prove they're side-effect-free. We can, so we alias
|
|
5365
|
+
// them here. Each alias saves bytes in the minified output, and the short
|
|
5366
|
+
// names also reduce visual noise in the hot paths (binding pipeline,
|
|
5367
|
+
// createDOM, etc.).
|
|
5368
|
+
//
|
|
5369
|
+
// Alias Target Sites
|
|
5370
|
+
// ───────── ────────────────────────────────────── ─────
|
|
5371
|
+
// _hop Object.prototype.hasOwnProperty 15
|
|
5372
|
+
// _isA Array.isArray 25
|
|
5373
|
+
// _keys Object.keys 7
|
|
5374
|
+
// _to bw.typeOf (type string) 26
|
|
5375
|
+
// _is type check boolean: _is(x,'string') ~50
|
|
5376
|
+
// _cw console.warn 8
|
|
5377
|
+
// _cl console.log 11
|
|
5378
|
+
// _ce console.error 4
|
|
5379
|
+
// _chp ComponentHandle.prototype 28 (defined after constructor)
|
|
5380
|
+
//
|
|
5381
|
+
// Note: document.createElement etc. are NOT aliased because they require
|
|
5382
|
+
// `this === document` and .bind() would add overhead on every call.
|
|
5383
|
+
// Console aliases use thin wrappers (not direct refs) so test monkey-
|
|
5384
|
+
// patching of console.warn/log/error continues to work.
|
|
5385
|
+
//
|
|
5386
|
+
// `typeof x` for UNDECLARED globals (window, document, process, require,
|
|
5387
|
+
// EventSource, navigator, Promise, __filename, import.meta) MUST stay as
|
|
5388
|
+
// raw `typeof` — calling _to(x) when x doesn't exist throws ReferenceError.
|
|
5389
|
+
//
|
|
5390
|
+
// ── v1 functional type helpers (kept for reference, not currently used) ──
|
|
5391
|
+
// _toa(x, type, trueVal, falseVal) — bw.typeAssign:
|
|
5392
|
+
// returns trueVal if _to(x)===type, else falseVal.
|
|
5393
|
+
// Replaces: (typeof x === 'string') ? A : B → _toa(x,'string',A,B)
|
|
5394
|
+
// _toc(x, type, trueVal, falseVal) — bw.typeConvert:
|
|
5395
|
+
// same as _toa but if trueVal/falseVal are functions, calls them with x.
|
|
5396
|
+
// Replaces: typeof x === 'string' ? fn(x) : default → _toc(x,'string',fn,default)
|
|
5397
|
+
// Uncomment if pattern frequency justifies them:
|
|
5398
|
+
// var _toa = function(x, t, y, n) { return _to(x) === t ? y : n; };
|
|
5399
|
+
// 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); };
|
|
5400
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
5401
|
+
var _hop = Object.prototype.hasOwnProperty;
|
|
5402
|
+
var _isA = Array.isArray;
|
|
5403
|
+
var _keys = Object.keys;
|
|
5404
|
+
var _to = typeOf; // imported from bitwrench-utils.js
|
|
5405
|
+
var _is = function _is(x, t) {
|
|
5406
|
+
var r = _to(x);
|
|
5407
|
+
return r === t || r.toLowerCase() === t;
|
|
5408
|
+
};
|
|
5409
|
+
// Console aliases use thin wrappers (not direct references) so that test
|
|
5410
|
+
// code can monkey-patch console.warn/log/error and the patches take effect.
|
|
5411
|
+
var _cw = function _cw() {
|
|
5412
|
+
console.warn.apply(console, arguments);
|
|
5413
|
+
};
|
|
5414
|
+
var _cl = function _cl() {
|
|
5415
|
+
console.log.apply(console, arguments);
|
|
5416
|
+
};
|
|
5417
|
+
var _ce = function _ce() {
|
|
5418
|
+
console.error.apply(console, arguments);
|
|
5419
|
+
};
|
|
5420
|
+
|
|
5421
|
+
/**
|
|
5422
|
+
* Debug flag. When true, emits console.warn for silent binding failures
|
|
5423
|
+
* (missing paths, null refs, auto-created intermediate objects).
|
|
5424
|
+
* @type {boolean}
|
|
5425
|
+
*/
|
|
5426
|
+
bw.debug = false;
|
|
5427
|
+
|
|
5176
5428
|
/**
|
|
5177
5429
|
* Lazy-resolve Node.js `fs` module.
|
|
5178
5430
|
* Tries require('fs') first (available in CJS/UMD Node.js builds),
|
|
@@ -5322,7 +5574,7 @@
|
|
|
5322
5574
|
*/
|
|
5323
5575
|
bw._el = function (id) {
|
|
5324
5576
|
// Pass-through for DOM elements
|
|
5325
|
-
if (
|
|
5577
|
+
if (!_is(id, 'string')) return id || null;
|
|
5326
5578
|
if (!id) return null;
|
|
5327
5579
|
if (!bw._isBrowser) return null;
|
|
5328
5580
|
|
|
@@ -5350,7 +5602,12 @@
|
|
|
5350
5602
|
el = document.querySelector('[data-bw_id="' + id + '"]');
|
|
5351
5603
|
}
|
|
5352
5604
|
|
|
5353
|
-
// 5.
|
|
5605
|
+
// 5. Try class-based lookup for bw_uuid_* tokens (UUID addressing)
|
|
5606
|
+
if (!el && id.indexOf('bw_uuid_') === 0) {
|
|
5607
|
+
el = document.querySelector('.' + id);
|
|
5608
|
+
}
|
|
5609
|
+
|
|
5610
|
+
// 6. Cache the result for next time
|
|
5354
5611
|
if (el) {
|
|
5355
5612
|
bw._nodeMap[id] = el;
|
|
5356
5613
|
}
|
|
@@ -5402,6 +5659,79 @@
|
|
|
5402
5659
|
}
|
|
5403
5660
|
};
|
|
5404
5661
|
|
|
5662
|
+
// ===================================================================================
|
|
5663
|
+
// bw.assignUUID() / bw.getUUID() — Explicit UUID addressing for TACO objects
|
|
5664
|
+
// ===================================================================================
|
|
5665
|
+
|
|
5666
|
+
/**
|
|
5667
|
+
* Regex to match a bw_uuid_* token in a class string.
|
|
5668
|
+
* @private
|
|
5669
|
+
*/
|
|
5670
|
+
var _UUID_RE = /\bbw_uuid_[a-z0-9_]+\b/;
|
|
5671
|
+
|
|
5672
|
+
/**
|
|
5673
|
+
* Assign a UUID to a TACO object by appending a `bw_uuid_*` token to `taco.a.class`.
|
|
5674
|
+
*
|
|
5675
|
+
* Idempotent by default — calling twice returns the same UUID. Pass `forceNew=true`
|
|
5676
|
+
* to replace an existing UUID (useful in loops where each TACO needs a unique ID).
|
|
5677
|
+
*
|
|
5678
|
+
* @param {Object} taco - A TACO object `{t, a, c, o}`
|
|
5679
|
+
* @param {boolean} [forceNew=false] - If true, replaces any existing UUID with a new one
|
|
5680
|
+
* @returns {string} The UUID string (e.g. 'bw_uuid_a1b2c3d4e5')
|
|
5681
|
+
* @category Identifiers
|
|
5682
|
+
* @example
|
|
5683
|
+
* var card = bw.makeStatCard({ value: '0', label: 'Scans' });
|
|
5684
|
+
* var uuid = bw.assignUUID(card); // 'bw_uuid_a1b2c3d4e5'
|
|
5685
|
+
* var same = bw.assignUUID(card); // same UUID (idempotent)
|
|
5686
|
+
* var diff = bw.assignUUID(card, true); // new UUID (forced)
|
|
5687
|
+
*/
|
|
5688
|
+
bw.assignUUID = function (taco, forceNew) {
|
|
5689
|
+
if (!taco || !_is(taco, 'object')) return null;
|
|
5690
|
+
|
|
5691
|
+
// Ensure taco.a exists
|
|
5692
|
+
if (!taco.a) taco.a = {};
|
|
5693
|
+
if (!_is(taco.a["class"], 'string')) taco.a["class"] = taco.a["class"] ? String(taco.a["class"]) : '';
|
|
5694
|
+
var existing = taco.a["class"].match(_UUID_RE);
|
|
5695
|
+
if (existing && !forceNew) {
|
|
5696
|
+
return existing[0];
|
|
5697
|
+
}
|
|
5698
|
+
|
|
5699
|
+
// Remove old UUID if forceNew
|
|
5700
|
+
if (existing) {
|
|
5701
|
+
taco.a["class"] = taco.a["class"].replace(_UUID_RE, '').replace(/\s+/g, ' ').trim();
|
|
5702
|
+
}
|
|
5703
|
+
var uuid = bw.uuid('uuid');
|
|
5704
|
+
taco.a["class"] = (taco.a["class"] ? taco.a["class"] + ' ' : '') + uuid;
|
|
5705
|
+
return uuid;
|
|
5706
|
+
};
|
|
5707
|
+
|
|
5708
|
+
/**
|
|
5709
|
+
* Read the UUID from a TACO object or DOM element. Pure getter, no side effects.
|
|
5710
|
+
*
|
|
5711
|
+
* @param {Object|Element} tacoOrElement - A TACO object or DOM element
|
|
5712
|
+
* @returns {string|null} The UUID string, or null if none assigned
|
|
5713
|
+
* @category Identifiers
|
|
5714
|
+
* @example
|
|
5715
|
+
* bw.getUUID(card) // 'bw_uuid_a1b2c3d4e5' (from TACO)
|
|
5716
|
+
* bw.getUUID(domEl) // 'bw_uuid_a1b2c3d4e5' (from DOM element)
|
|
5717
|
+
* bw.getUUID({t:'div'}) // null (no UUID)
|
|
5718
|
+
*/
|
|
5719
|
+
bw.getUUID = function (tacoOrElement) {
|
|
5720
|
+
if (!tacoOrElement) return null;
|
|
5721
|
+
var classStr;
|
|
5722
|
+
// DOM element: check className
|
|
5723
|
+
if (tacoOrElement.className !== undefined && tacoOrElement.tagName) {
|
|
5724
|
+
classStr = tacoOrElement.className;
|
|
5725
|
+
}
|
|
5726
|
+
// TACO object: check a.class
|
|
5727
|
+
else if (tacoOrElement.a && _is(tacoOrElement.a["class"], 'string')) {
|
|
5728
|
+
classStr = tacoOrElement.a["class"];
|
|
5729
|
+
}
|
|
5730
|
+
if (!classStr) return null;
|
|
5731
|
+
var match = classStr.match(_UUID_RE);
|
|
5732
|
+
return match ? match[0] : null;
|
|
5733
|
+
};
|
|
5734
|
+
|
|
5405
5735
|
/**
|
|
5406
5736
|
* Escape HTML special characters to prevent XSS.
|
|
5407
5737
|
*
|
|
@@ -5417,7 +5747,7 @@
|
|
|
5417
5747
|
* // => '<b>Hello</b> & "world"'
|
|
5418
5748
|
*/
|
|
5419
5749
|
bw.escapeHTML = function (str) {
|
|
5420
|
-
if (
|
|
5750
|
+
if (!_is(str, 'string')) return '';
|
|
5421
5751
|
var escapeMap = {
|
|
5422
5752
|
'&': '&',
|
|
5423
5753
|
'<': '<',
|
|
@@ -5454,6 +5784,45 @@
|
|
|
5454
5784
|
};
|
|
5455
5785
|
};
|
|
5456
5786
|
|
|
5787
|
+
/**
|
|
5788
|
+
* Hyperscript-style TACO constructor.
|
|
5789
|
+
*
|
|
5790
|
+
* A convenience helper that returns a canonical TACO object from positional
|
|
5791
|
+
* arguments. The return value is a plain object — serializable, works with
|
|
5792
|
+
* bwserve, and accepted everywhere TACO is accepted.
|
|
5793
|
+
*
|
|
5794
|
+
* @param {string} tag - HTML tag name (e.g. 'div', 'p', 'section')
|
|
5795
|
+
* @param {Object|null} [attrs] - HTML attributes object. Pass null or omit to skip.
|
|
5796
|
+
* @param {*} [content] - Content: string, number, TACO object, or array of children.
|
|
5797
|
+
* @param {Object} [options] - TACO options (state, lifecycle hooks, render fn).
|
|
5798
|
+
* @returns {Object} Plain TACO object {t, a?, c?, o?}
|
|
5799
|
+
* @category Utilities
|
|
5800
|
+
* @see bw.html
|
|
5801
|
+
* @see bw.createDOM
|
|
5802
|
+
* @see bw.DOM
|
|
5803
|
+
* @example
|
|
5804
|
+
* bw.h('div')
|
|
5805
|
+
* // => { t: 'div' }
|
|
5806
|
+
*
|
|
5807
|
+
* bw.h('p', { class: 'bw_text_muted' }, 'Hello')
|
|
5808
|
+
* // => { t: 'p', a: { class: 'bw_text_muted' }, c: 'Hello' }
|
|
5809
|
+
*
|
|
5810
|
+
* bw.h('ul', null, [
|
|
5811
|
+
* bw.h('li', null, 'one'),
|
|
5812
|
+
* bw.h('li', null, 'two')
|
|
5813
|
+
* ])
|
|
5814
|
+
* // => { t: 'ul', c: [{ t: 'li', c: 'one' }, { t: 'li', c: 'two' }] }
|
|
5815
|
+
*/
|
|
5816
|
+
bw.h = function (tag, attrs, content, options) {
|
|
5817
|
+
var taco = {
|
|
5818
|
+
t: String(tag)
|
|
5819
|
+
};
|
|
5820
|
+
if (attrs !== null && attrs !== undefined) taco.a = attrs;
|
|
5821
|
+
if (content !== undefined) taco.c = content;
|
|
5822
|
+
if (options !== undefined) taco.o = options;
|
|
5823
|
+
return taco;
|
|
5824
|
+
};
|
|
5825
|
+
|
|
5457
5826
|
/**
|
|
5458
5827
|
* Convert a TACO object (or array of TACOs) to an HTML string.
|
|
5459
5828
|
*
|
|
@@ -5494,7 +5863,7 @@
|
|
|
5494
5863
|
}
|
|
5495
5864
|
|
|
5496
5865
|
// Handle arrays of TACOs
|
|
5497
|
-
if (
|
|
5866
|
+
if (_isA(taco)) {
|
|
5498
5867
|
return taco.map(function (t) {
|
|
5499
5868
|
return bw.html(t, options);
|
|
5500
5869
|
}).join('');
|
|
@@ -5517,17 +5886,17 @@
|
|
|
5517
5886
|
if (taco && taco._bwEach && options.state) {
|
|
5518
5887
|
var eachExpr = taco.expr.replace(/^\$\{|\}$/g, '');
|
|
5519
5888
|
var arr = bw._evaluatePath(options.state, eachExpr);
|
|
5520
|
-
if (!
|
|
5889
|
+
if (!_isA(arr)) return '';
|
|
5521
5890
|
return arr.map(function (item, idx) {
|
|
5522
5891
|
return bw.html(taco.factory(item, idx), options);
|
|
5523
5892
|
}).join('');
|
|
5524
5893
|
}
|
|
5525
5894
|
|
|
5526
5895
|
// Handle primitives and non-TACO objects
|
|
5527
|
-
if (
|
|
5896
|
+
if (!_is(taco, 'object') || !taco.t) {
|
|
5528
5897
|
var str = options.raw ? String(taco) : bw.escapeHTML(String(taco));
|
|
5529
5898
|
// Resolve template bindings if state provided
|
|
5530
|
-
if (options.state &&
|
|
5899
|
+
if (options.state && _is(str, 'string') && str.indexOf('${') >= 0) {
|
|
5531
5900
|
str = bw._resolveTemplate(str, options.state, !!options.compile);
|
|
5532
5901
|
}
|
|
5533
5902
|
return str;
|
|
@@ -5552,9 +5921,17 @@
|
|
|
5552
5921
|
// Skip null, undefined, false
|
|
5553
5922
|
if (value == null || value === false) continue;
|
|
5554
5923
|
|
|
5555
|
-
//
|
|
5556
|
-
if (key.startsWith('on'))
|
|
5557
|
-
|
|
5924
|
+
// Serialize event handlers via funcRegister
|
|
5925
|
+
if (key.startsWith('on')) {
|
|
5926
|
+
if (_is(value, 'function')) {
|
|
5927
|
+
var fnId = bw.funcRegister(value);
|
|
5928
|
+
attrStr += ' ' + key + '="' + bw.funcGetDispatchStr(fnId, 'event') + '"';
|
|
5929
|
+
} else if (_is(value, 'string')) {
|
|
5930
|
+
attrStr += ' ' + key + '="' + bw.escapeHTML(value) + '"';
|
|
5931
|
+
}
|
|
5932
|
+
continue;
|
|
5933
|
+
}
|
|
5934
|
+
if (key === 'style' && _is(value, 'object')) {
|
|
5558
5935
|
// Convert style object to string
|
|
5559
5936
|
var styleStr = Object.entries(value).filter(function (_ref) {
|
|
5560
5937
|
var _ref2 = _slicedToArray(_ref, 2),
|
|
@@ -5571,7 +5948,7 @@
|
|
|
5571
5948
|
}
|
|
5572
5949
|
} else if (key === 'class') {
|
|
5573
5950
|
// Handle class as array or string
|
|
5574
|
-
var classStr =
|
|
5951
|
+
var classStr = _isA(value) ? value.filter(Boolean).join(' ') : String(value);
|
|
5575
5952
|
if (classStr) {
|
|
5576
5953
|
attrStr += " class=\"".concat(bw.escapeHTML(classStr), "\"");
|
|
5577
5954
|
}
|
|
@@ -5607,12 +5984,182 @@
|
|
|
5607
5984
|
// Process content recursively
|
|
5608
5985
|
var contentStr = content != null ? bw.html(content, options) : '';
|
|
5609
5986
|
// Resolve template bindings in content if state provided
|
|
5610
|
-
if (options.state &&
|
|
5987
|
+
if (options.state && _is(contentStr, 'string') && contentStr.indexOf('${') >= 0) {
|
|
5611
5988
|
contentStr = bw._resolveTemplate(contentStr, options.state, !!options.compile);
|
|
5612
5989
|
}
|
|
5613
5990
|
return "<".concat(tag).concat(attrStr, ">").concat(contentStr, "</").concat(tag, ">");
|
|
5614
5991
|
};
|
|
5615
5992
|
|
|
5993
|
+
/**
|
|
5994
|
+
* Generate a complete, self-contained HTML document from TACO content.
|
|
5995
|
+
*
|
|
5996
|
+
* Produces a full `<!DOCTYPE html>` page with configurable runtime injection,
|
|
5997
|
+
* func registry emission (so serialized event handlers work), optional theme,
|
|
5998
|
+
* and extra head elements. Designed for static site generation, offline/airgapped
|
|
5999
|
+
* use, and the "static site that isn't static" workflow.
|
|
6000
|
+
*
|
|
6001
|
+
* @param {Object} [opts={}] - Page options
|
|
6002
|
+
* @param {Object|string|Array} [opts.body=''] - Body content: TACO, string, or array
|
|
6003
|
+
* @param {string} [opts.title='bitwrench'] - Page title
|
|
6004
|
+
* @param {Object} [opts.state] - State for ${expr} resolution in bw.html()
|
|
6005
|
+
* @param {string} [opts.runtime='shim'] - Runtime level: 'inline'|'cdn'|'shim'|'none'
|
|
6006
|
+
* @param {string} [opts.css=''] - Additional CSS for <style> block
|
|
6007
|
+
* @param {string|Object} [opts.theme=null] - Theme preset name or config object
|
|
6008
|
+
* @param {Array} [opts.head=[]] - Extra TACO elements rendered into <head>
|
|
6009
|
+
* @param {string} [opts.favicon=''] - Favicon URL
|
|
6010
|
+
* @param {string} [opts.lang='en'] - HTML lang attribute
|
|
6011
|
+
* @returns {string} Complete HTML document string
|
|
6012
|
+
* @category DOM Generation
|
|
6013
|
+
* @see bw.html
|
|
6014
|
+
* @example
|
|
6015
|
+
* bw.htmlPage({
|
|
6016
|
+
* title: 'My App',
|
|
6017
|
+
* body: { t: 'h1', c: 'Hello World' },
|
|
6018
|
+
* runtime: 'shim'
|
|
6019
|
+
* })
|
|
6020
|
+
*/
|
|
6021
|
+
bw.htmlPage = function (opts) {
|
|
6022
|
+
opts = opts || {};
|
|
6023
|
+
var title = opts.title || 'bitwrench';
|
|
6024
|
+
var body = opts.body || '';
|
|
6025
|
+
var state = opts.state || undefined;
|
|
6026
|
+
var runtime = opts.runtime || 'shim';
|
|
6027
|
+
var css = opts.css || '';
|
|
6028
|
+
var theme = opts.theme || null;
|
|
6029
|
+
var headExtra = opts.head || [];
|
|
6030
|
+
var favicon = opts.favicon || '';
|
|
6031
|
+
var lang = opts.lang || 'en';
|
|
6032
|
+
|
|
6033
|
+
// Snapshot funcRegistry counter before rendering
|
|
6034
|
+
var fnCounterBefore = bw._fnIDCounter;
|
|
6035
|
+
|
|
6036
|
+
// Render body content
|
|
6037
|
+
var bodyHTML = '';
|
|
6038
|
+
if (_is(body, 'string')) {
|
|
6039
|
+
bodyHTML = body;
|
|
6040
|
+
} else {
|
|
6041
|
+
var htmlOpts = {};
|
|
6042
|
+
if (state) htmlOpts.state = state;
|
|
6043
|
+
bodyHTML = bw.html(body, htmlOpts);
|
|
6044
|
+
}
|
|
6045
|
+
|
|
6046
|
+
// Collect functions registered during this render
|
|
6047
|
+
var fnCounterAfter = bw._fnIDCounter;
|
|
6048
|
+
var registryEntries = '';
|
|
6049
|
+
for (var i = fnCounterBefore; i < fnCounterAfter; i++) {
|
|
6050
|
+
var fnKey = 'bw_fn_' + i;
|
|
6051
|
+
if (bw._fnRegistry[fnKey]) {
|
|
6052
|
+
registryEntries += 'bw._fnRegistry[\'' + fnKey + '\']=' + bw._fnRegistry[fnKey].toString() + ';\n';
|
|
6053
|
+
}
|
|
6054
|
+
}
|
|
6055
|
+
|
|
6056
|
+
// Build runtime script for <head>
|
|
6057
|
+
var runtimeHead = '';
|
|
6058
|
+
if (runtime === 'inline') {
|
|
6059
|
+
// Read UMD bundle synchronously if in Node.js
|
|
6060
|
+
var umdSource = null;
|
|
6061
|
+
if (bw._isNode) {
|
|
6062
|
+
try {
|
|
6063
|
+
var fs = typeof require === 'function' ? require('fs') : null;
|
|
6064
|
+
var pathMod = typeof require === 'function' ? require('path') : null;
|
|
6065
|
+
if (fs && pathMod) {
|
|
6066
|
+
// Resolve dist/ relative to this source file
|
|
6067
|
+
var srcDir = '';
|
|
6068
|
+
try {
|
|
6069
|
+
srcDir = pathMod.dirname(typeof __filename !== 'undefined' ? __filename : '');
|
|
6070
|
+
} catch (e2) {/* ESM: __filename not available */}
|
|
6071
|
+
if (!srcDir && typeof ({ url: (typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bitwrench-lean.es5.js', document.baseURI).href)) }) !== 'undefined' && (typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bitwrench-lean.es5.js', document.baseURI).href))) {
|
|
6072
|
+
var url = typeof require === 'function' ? require('url') : null;
|
|
6073
|
+
if (url && url.fileURLToPath) srcDir = pathMod.dirname(url.fileURLToPath((typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bitwrench-lean.es5.js', document.baseURI).href))));
|
|
6074
|
+
}
|
|
6075
|
+
if (srcDir) {
|
|
6076
|
+
var distPath = pathMod.resolve(srcDir, '../dist/bitwrench.umd.min.js');
|
|
6077
|
+
umdSource = fs.readFileSync(distPath, 'utf8');
|
|
6078
|
+
}
|
|
6079
|
+
}
|
|
6080
|
+
} catch (e) {/* fall through */}
|
|
6081
|
+
}
|
|
6082
|
+
if (umdSource) {
|
|
6083
|
+
runtimeHead = '<script>' + umdSource + '</script>';
|
|
6084
|
+
} else {
|
|
6085
|
+
// Fallback to shim in browser or if dist not available
|
|
6086
|
+
runtimeHead = '<script>' + bw._FUNC_REGISTRY_SHIM + '</script>';
|
|
6087
|
+
}
|
|
6088
|
+
} else if (runtime === 'cdn') {
|
|
6089
|
+
runtimeHead = '<script src="https://cdn.jsdelivr.net/npm/bitwrench@2/dist/bitwrench.umd.min.js"></script>';
|
|
6090
|
+
} else if (runtime === 'shim') {
|
|
6091
|
+
runtimeHead = '<script>' + bw._FUNC_REGISTRY_SHIM + '</script>';
|
|
6092
|
+
}
|
|
6093
|
+
// runtime === 'none' → empty
|
|
6094
|
+
|
|
6095
|
+
// Theme CSS
|
|
6096
|
+
var themeCSS = '';
|
|
6097
|
+
if (theme) {
|
|
6098
|
+
var themeConfig = _is(theme, 'string') ? THEME_PRESETS[theme.toLowerCase()] || null : theme;
|
|
6099
|
+
if (themeConfig) {
|
|
6100
|
+
var themeResult = bw.makeStyles(themeConfig);
|
|
6101
|
+
themeCSS = themeResult.css;
|
|
6102
|
+
}
|
|
6103
|
+
}
|
|
6104
|
+
|
|
6105
|
+
// Extra <head> elements
|
|
6106
|
+
var headHTML = '';
|
|
6107
|
+
if (_isA(headExtra) && headExtra.length > 0) {
|
|
6108
|
+
headHTML = headExtra.map(function (el) {
|
|
6109
|
+
return bw.html(el);
|
|
6110
|
+
}).join('\n');
|
|
6111
|
+
}
|
|
6112
|
+
|
|
6113
|
+
// Favicon
|
|
6114
|
+
var faviconTag = '';
|
|
6115
|
+
if (favicon) {
|
|
6116
|
+
var safeFavicon = favicon.replace(/[&<>"']/g, function (c) {
|
|
6117
|
+
return {
|
|
6118
|
+
'&': '&',
|
|
6119
|
+
'<': '<',
|
|
6120
|
+
'>': '>',
|
|
6121
|
+
'"': '"',
|
|
6122
|
+
"'": '''
|
|
6123
|
+
}[c];
|
|
6124
|
+
});
|
|
6125
|
+
faviconTag = '<link rel="icon" href="' + safeFavicon + '">';
|
|
6126
|
+
}
|
|
6127
|
+
|
|
6128
|
+
// Escaped title
|
|
6129
|
+
var safeTitle = bw.escapeHTML(title);
|
|
6130
|
+
|
|
6131
|
+
// Combine all CSS
|
|
6132
|
+
var allCSS = (themeCSS ? themeCSS + '\n' : '') + css;
|
|
6133
|
+
|
|
6134
|
+
// Body-end script: registry entries + optional loadStyles
|
|
6135
|
+
var bodyEndScript = '';
|
|
6136
|
+
var bodyEndParts = [];
|
|
6137
|
+
if (registryEntries) {
|
|
6138
|
+
bodyEndParts.push(registryEntries);
|
|
6139
|
+
}
|
|
6140
|
+
if (runtime === 'inline' || runtime === 'cdn') {
|
|
6141
|
+
bodyEndParts.push('if(typeof bw!=="undefined"){bw.loadStyles();}');
|
|
6142
|
+
}
|
|
6143
|
+
if (bodyEndParts.length > 0) {
|
|
6144
|
+
bodyEndScript = '<script>\n' + bodyEndParts.join('\n') + '\n</script>';
|
|
6145
|
+
}
|
|
6146
|
+
|
|
6147
|
+
// Assemble document
|
|
6148
|
+
var parts = ['<!DOCTYPE html>', '<html lang="' + lang + '">', '<head>', '<meta charset="UTF-8">', '<meta name="viewport" content="width=device-width, initial-scale=1">'];
|
|
6149
|
+
parts.push('<title>' + safeTitle + '</title>');
|
|
6150
|
+
if (faviconTag) parts.push(faviconTag);
|
|
6151
|
+
if (runtimeHead) parts.push(runtimeHead);
|
|
6152
|
+
if (headHTML) parts.push(headHTML);
|
|
6153
|
+
if (allCSS) parts.push('<style>' + allCSS + '</style>');
|
|
6154
|
+
parts.push('</head>');
|
|
6155
|
+
parts.push('<body>');
|
|
6156
|
+
parts.push(bodyHTML);
|
|
6157
|
+
if (bodyEndScript) parts.push(bodyEndScript);
|
|
6158
|
+
parts.push('</body>');
|
|
6159
|
+
parts.push('</html>');
|
|
6160
|
+
return parts.join('\n');
|
|
6161
|
+
};
|
|
6162
|
+
|
|
5616
6163
|
/**
|
|
5617
6164
|
* Create a live DOM element from a TACO object (browser only).
|
|
5618
6165
|
*
|
|
@@ -5658,7 +6205,7 @@
|
|
|
5658
6205
|
}
|
|
5659
6206
|
|
|
5660
6207
|
// Handle text nodes
|
|
5661
|
-
if (
|
|
6208
|
+
if (!_is(taco, 'object') || !taco.t) {
|
|
5662
6209
|
return document.createTextNode(String(taco));
|
|
5663
6210
|
}
|
|
5664
6211
|
var tag = taco.t,
|
|
@@ -5677,16 +6224,16 @@
|
|
|
5677
6224
|
key = _Object$entries2$_i[0],
|
|
5678
6225
|
value = _Object$entries2$_i[1];
|
|
5679
6226
|
if (value == null || value === false) continue;
|
|
5680
|
-
if (key === 'style' &&
|
|
6227
|
+
if (key === 'style' && _is(value, 'object')) {
|
|
5681
6228
|
// Apply styles directly
|
|
5682
6229
|
Object.assign(el.style, value);
|
|
5683
6230
|
} else if (key === 'class') {
|
|
5684
6231
|
// Handle class as array or string
|
|
5685
|
-
var classStr =
|
|
6232
|
+
var classStr = _isA(value) ? value.filter(Boolean).join(' ') : String(value);
|
|
5686
6233
|
if (classStr) {
|
|
5687
6234
|
el.className = classStr;
|
|
5688
6235
|
}
|
|
5689
|
-
} else if (key.startsWith('on') &&
|
|
6236
|
+
} else if (key.startsWith('on') && _is(value, 'function')) {
|
|
5690
6237
|
// Event handlers
|
|
5691
6238
|
var eventName = key.slice(2).toLowerCase();
|
|
5692
6239
|
el.addEventListener(eventName, value);
|
|
@@ -5706,7 +6253,7 @@
|
|
|
5706
6253
|
// Children with data-bw_id or id attributes get local refs on the parent,
|
|
5707
6254
|
// so o.render functions can access them without any DOM lookup.
|
|
5708
6255
|
if (content != null) {
|
|
5709
|
-
if (
|
|
6256
|
+
if (_isA(content)) {
|
|
5710
6257
|
content.forEach(function (child) {
|
|
5711
6258
|
if (child != null) {
|
|
5712
6259
|
// Handle ComponentHandle in content arrays (Level 2 children)
|
|
@@ -5726,20 +6273,20 @@
|
|
|
5726
6273
|
if (childEl._bw_refs) {
|
|
5727
6274
|
if (!el._bw_refs) el._bw_refs = {};
|
|
5728
6275
|
for (var rk in childEl._bw_refs) {
|
|
5729
|
-
if (
|
|
6276
|
+
if (_hop.call(childEl._bw_refs, rk)) {
|
|
5730
6277
|
el._bw_refs[rk] = childEl._bw_refs[rk];
|
|
5731
6278
|
}
|
|
5732
6279
|
}
|
|
5733
6280
|
}
|
|
5734
6281
|
}
|
|
5735
6282
|
});
|
|
5736
|
-
} else if (
|
|
6283
|
+
} else if (_is(content, 'object') && content.__bw_raw) {
|
|
5737
6284
|
// Raw HTML content — inject via innerHTML
|
|
5738
6285
|
el.innerHTML = content.v;
|
|
5739
6286
|
} else if (content._bwComponent === true) {
|
|
5740
6287
|
// Single ComponentHandle as content
|
|
5741
6288
|
content.mount(el);
|
|
5742
|
-
} else if (
|
|
6289
|
+
} else if (_is(content, 'object') && content.t) {
|
|
5743
6290
|
var childEl = bw.createDOM(content, options);
|
|
5744
6291
|
el.appendChild(childEl);
|
|
5745
6292
|
var childBwId = content.a ? content.a['data-bw_id'] || content.a.id : null;
|
|
@@ -5750,7 +6297,7 @@
|
|
|
5750
6297
|
if (childEl._bw_refs) {
|
|
5751
6298
|
if (!el._bw_refs) el._bw_refs = {};
|
|
5752
6299
|
for (var rk in childEl._bw_refs) {
|
|
5753
|
-
if (
|
|
6300
|
+
if (_hop.call(childEl._bw_refs, rk)) {
|
|
5754
6301
|
el._bw_refs[rk] = childEl._bw_refs[rk];
|
|
5755
6302
|
}
|
|
5756
6303
|
}
|
|
@@ -5765,6 +6312,14 @@
|
|
|
5765
6312
|
bw._registerNode(el, null);
|
|
5766
6313
|
}
|
|
5767
6314
|
|
|
6315
|
+
// Register UUID class in node cache (bw_uuid_* tokens in class string)
|
|
6316
|
+
if (el.className) {
|
|
6317
|
+
var uuidMatch = el.className.match(_UUID_RE);
|
|
6318
|
+
if (uuidMatch) {
|
|
6319
|
+
bw._nodeMap[uuidMatch[0]] = el;
|
|
6320
|
+
}
|
|
6321
|
+
}
|
|
6322
|
+
|
|
5768
6323
|
// Handle lifecycle hooks and state
|
|
5769
6324
|
if (opts.mounted || opts.unmount || opts.render || opts.state) {
|
|
5770
6325
|
var id = attrs['data-bw_id'] || bw.uuid();
|
|
@@ -5782,7 +6337,7 @@
|
|
|
5782
6337
|
if (opts.render) {
|
|
5783
6338
|
el._bw_render = opts.render;
|
|
5784
6339
|
if (opts.mounted) {
|
|
5785
|
-
|
|
6340
|
+
_cw('bw.createDOM: o.render and o.mounted are mutually exclusive. o.render wins.');
|
|
5786
6341
|
}
|
|
5787
6342
|
|
|
5788
6343
|
// Queue initial render (same timing as mounted)
|
|
@@ -5854,7 +6409,7 @@
|
|
|
5854
6409
|
// Get target element (use cache-backed lookup)
|
|
5855
6410
|
var targetEl = bw._el(target);
|
|
5856
6411
|
if (!targetEl) {
|
|
5857
|
-
|
|
6412
|
+
_ce('bw.DOM: Target element not found:', target);
|
|
5858
6413
|
return null;
|
|
5859
6414
|
}
|
|
5860
6415
|
|
|
@@ -5892,7 +6447,7 @@
|
|
|
5892
6447
|
targetEl.appendChild(taco.element);
|
|
5893
6448
|
}
|
|
5894
6449
|
// Handle arrays
|
|
5895
|
-
else if (
|
|
6450
|
+
else if (_isA(taco)) {
|
|
5896
6451
|
taco.forEach(function (t) {
|
|
5897
6452
|
if (t != null) {
|
|
5898
6453
|
if (t._bwComponent === true) {
|
|
@@ -5927,7 +6482,7 @@
|
|
|
5927
6482
|
bw.compileProps = function (handle) {
|
|
5928
6483
|
var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
5929
6484
|
var compiledProps = {};
|
|
5930
|
-
|
|
6485
|
+
_keys(props).forEach(function (key) {
|
|
5931
6486
|
// Create getter/setter for each prop
|
|
5932
6487
|
Object.defineProperty(compiledProps, key, {
|
|
5933
6488
|
get: function get() {
|
|
@@ -6124,6 +6679,16 @@
|
|
|
6124
6679
|
bw.cleanup = function (element) {
|
|
6125
6680
|
if (!bw._isBrowser || !element) return;
|
|
6126
6681
|
|
|
6682
|
+
// Deregister UUID classes from node cache (element + descendants)
|
|
6683
|
+
// Covers elements that have UUID but no data-bw_id
|
|
6684
|
+
var selfUuidMatch = element.className && element.className.match(_UUID_RE);
|
|
6685
|
+
if (selfUuidMatch) delete bw._nodeMap[selfUuidMatch[0]];
|
|
6686
|
+
var uuidEls = element.querySelectorAll('[class*="bw_uuid_"]');
|
|
6687
|
+
uuidEls.forEach(function (uel) {
|
|
6688
|
+
var m = uel.className && uel.className.match(_UUID_RE);
|
|
6689
|
+
if (m) delete bw._nodeMap[m[0]];
|
|
6690
|
+
});
|
|
6691
|
+
|
|
6127
6692
|
// Find all elements with data-bw_id
|
|
6128
6693
|
var elements = element.querySelectorAll('[data-bw_id]');
|
|
6129
6694
|
elements.forEach(function (el) {
|
|
@@ -6137,6 +6702,10 @@
|
|
|
6137
6702
|
// Deregister from node cache
|
|
6138
6703
|
bw._deregisterNode(el, id);
|
|
6139
6704
|
|
|
6705
|
+
// Deregister UUID class from node cache
|
|
6706
|
+
var uuidMatch = el.className && el.className.match(_UUID_RE);
|
|
6707
|
+
if (uuidMatch) delete bw._nodeMap[uuidMatch[0]];
|
|
6708
|
+
|
|
6140
6709
|
// Clean up pub/sub subscriptions tied to this element
|
|
6141
6710
|
if (el._bw_subs) {
|
|
6142
6711
|
el._bw_subs.forEach(function (unsub) {
|
|
@@ -6163,6 +6732,10 @@
|
|
|
6163
6732
|
// Deregister from node cache
|
|
6164
6733
|
bw._deregisterNode(element, id);
|
|
6165
6734
|
|
|
6735
|
+
// Deregister UUID class from node cache
|
|
6736
|
+
var elemUuidMatch = element.className && element.className.match(_UUID_RE);
|
|
6737
|
+
if (elemUuidMatch) delete bw._nodeMap[elemUuidMatch[0]];
|
|
6738
|
+
|
|
6166
6739
|
// Clean up pub/sub subscriptions tied to element itself
|
|
6167
6740
|
if (element._bw_subs) {
|
|
6168
6741
|
element._bw_subs.forEach(function (unsub) {
|
|
@@ -6238,17 +6811,17 @@
|
|
|
6238
6811
|
if (attr) {
|
|
6239
6812
|
// Patch an attribute
|
|
6240
6813
|
el.setAttribute(attr, String(content));
|
|
6241
|
-
} else if (
|
|
6814
|
+
} else if (_isA(content)) {
|
|
6242
6815
|
// Patch with array of children (strings and/or TACOs)
|
|
6243
6816
|
el.innerHTML = '';
|
|
6244
6817
|
content.forEach(function (item) {
|
|
6245
|
-
if (
|
|
6818
|
+
if (_is(item, 'string') || _is(item, 'number')) {
|
|
6246
6819
|
el.appendChild(document.createTextNode(String(item)));
|
|
6247
6820
|
} else if (item && item.t) {
|
|
6248
6821
|
el.appendChild(bw.createDOM(item));
|
|
6249
6822
|
}
|
|
6250
6823
|
});
|
|
6251
|
-
} else if (
|
|
6824
|
+
} else if (_is(content, 'object') && content.t) {
|
|
6252
6825
|
// Patch with a TACO — replace children
|
|
6253
6826
|
el.innerHTML = '';
|
|
6254
6827
|
el.appendChild(bw.createDOM(content));
|
|
@@ -6279,7 +6852,7 @@
|
|
|
6279
6852
|
bw.patchAll = function (patches) {
|
|
6280
6853
|
var results = {};
|
|
6281
6854
|
for (var id in patches) {
|
|
6282
|
-
if (
|
|
6855
|
+
if (_hop.call(patches, id)) {
|
|
6283
6856
|
results[id] = bw.patch(id, patches[id]);
|
|
6284
6857
|
}
|
|
6285
6858
|
}
|
|
@@ -6376,7 +6949,7 @@
|
|
|
6376
6949
|
snapshot[i].handler(detail);
|
|
6377
6950
|
called++;
|
|
6378
6951
|
} catch (err) {
|
|
6379
|
-
|
|
6952
|
+
_cw('bw.pub: subscriber error on topic "' + topic + '":', err);
|
|
6380
6953
|
}
|
|
6381
6954
|
}
|
|
6382
6955
|
return called;
|
|
@@ -6477,8 +7050,8 @@
|
|
|
6477
7050
|
* @see bw.funcGetDispatchStr
|
|
6478
7051
|
*/
|
|
6479
7052
|
bw.funcRegister = function (fn, name) {
|
|
6480
|
-
if (
|
|
6481
|
-
var fnID =
|
|
7053
|
+
if (!_is(fn, 'function')) return '';
|
|
7054
|
+
var fnID = _is(name, 'string') && name.length > 0 ? name : 'bw_fn_' + bw._fnIDCounter++;
|
|
6482
7055
|
bw._fnRegistry[fnID] = fn;
|
|
6483
7056
|
return fnID;
|
|
6484
7057
|
};
|
|
@@ -6497,8 +7070,8 @@
|
|
|
6497
7070
|
bw.funcGetById = function (name, errFn) {
|
|
6498
7071
|
name = String(name);
|
|
6499
7072
|
if (name in bw._fnRegistry) return bw._fnRegistry[name];
|
|
6500
|
-
return
|
|
6501
|
-
|
|
7073
|
+
return _is(errFn, 'function') ? errFn : function () {
|
|
7074
|
+
_cw('bw.funcGetById: unregistered fn "' + name + '"');
|
|
6502
7075
|
};
|
|
6503
7076
|
};
|
|
6504
7077
|
|
|
@@ -6540,13 +7113,23 @@
|
|
|
6540
7113
|
bw.funcGetRegistry = function () {
|
|
6541
7114
|
var copy = {};
|
|
6542
7115
|
for (var k in bw._fnRegistry) {
|
|
6543
|
-
if (
|
|
7116
|
+
if (_hop.call(bw._fnRegistry, k)) {
|
|
6544
7117
|
copy[k] = bw._fnRegistry[k];
|
|
6545
7118
|
}
|
|
6546
7119
|
}
|
|
6547
7120
|
return copy;
|
|
6548
7121
|
};
|
|
6549
7122
|
|
|
7123
|
+
/**
|
|
7124
|
+
* Minimal runtime shim for funcRegister dispatch in static HTML.
|
|
7125
|
+
* When embedded in a `<script>` tag, provides just enough infrastructure
|
|
7126
|
+
* for `bw.funcGetById()` calls to resolve. The actual function bodies
|
|
7127
|
+
* are emitted separately as `bw._fnRegistry['bw_fn_X'] = ...;` assignments.
|
|
7128
|
+
* @type {string}
|
|
7129
|
+
* @category Function Registry
|
|
7130
|
+
*/
|
|
7131
|
+
bw._FUNC_REGISTRY_SHIM = '(function(){var bw=window.bw||(window.bw={});' + 'if(!bw._fnRegistry)bw._fnRegistry={};' + 'bw.funcGetById=function(n){return bw._fnRegistry[n]||function(){' + 'console.warn("bw: unregistered fn "+n)};};' + 'bw.funcRegister=function(fn,name){' + 'var id=name||("bw_fn_"+(bw._fnIDCounter=(bw._fnIDCounter||0)+1));' + 'bw._fnRegistry[id]=fn;return id;};' + 'window.bw=bw;})();';
|
|
7132
|
+
|
|
6550
7133
|
// ===================================================================================
|
|
6551
7134
|
// Template Binding Utilities
|
|
6552
7135
|
// ===================================================================================
|
|
@@ -6578,7 +7161,10 @@
|
|
|
6578
7161
|
var parts = path.split('.');
|
|
6579
7162
|
var val = state;
|
|
6580
7163
|
for (var i = 0; i < parts.length; i++) {
|
|
6581
|
-
if (val == null)
|
|
7164
|
+
if (val == null) {
|
|
7165
|
+
if (bw.debug) _cw('bw.debug: _evaluatePath — null at key "' + parts[i] + '" in path "' + path + '"');
|
|
7166
|
+
return '';
|
|
7167
|
+
}
|
|
6582
7168
|
val = val[parts[i]];
|
|
6583
7169
|
}
|
|
6584
7170
|
return val == null ? '' : val;
|
|
@@ -6598,7 +7184,7 @@
|
|
|
6598
7184
|
*/
|
|
6599
7185
|
bw._compiledExprs = {};
|
|
6600
7186
|
bw._resolveTemplate = function (str, state, compile) {
|
|
6601
|
-
if (
|
|
7187
|
+
if (!_is(str, 'string') || str.indexOf('${') < 0) return str;
|
|
6602
7188
|
var bindings = bw._parseBindings(str);
|
|
6603
7189
|
if (bindings.length === 0) return str;
|
|
6604
7190
|
var result = '';
|
|
@@ -6621,6 +7207,7 @@
|
|
|
6621
7207
|
try {
|
|
6622
7208
|
val = bw._compiledExprs[b.expr](state);
|
|
6623
7209
|
} catch (e) {
|
|
7210
|
+
if (bw.debug) _cw('bw.debug: _resolveTemplate — Tier 2 eval failed for "${' + b.expr + '}":', e.message);
|
|
6624
7211
|
val = '';
|
|
6625
7212
|
}
|
|
6626
7213
|
} else {
|
|
@@ -6728,7 +7315,7 @@
|
|
|
6728
7315
|
this._state = {};
|
|
6729
7316
|
if (o.state) {
|
|
6730
7317
|
for (var k in o.state) {
|
|
6731
|
-
if (
|
|
7318
|
+
if (_hop.call(o.state, k)) {
|
|
6732
7319
|
this._state[k] = o.state[k];
|
|
6733
7320
|
}
|
|
6734
7321
|
}
|
|
@@ -6737,7 +7324,7 @@
|
|
|
6737
7324
|
this._actions = {};
|
|
6738
7325
|
if (o.actions) {
|
|
6739
7326
|
for (var k2 in o.actions) {
|
|
6740
|
-
if (
|
|
7327
|
+
if (_hop.call(o.actions, k2)) {
|
|
6741
7328
|
this._actions[k2] = o.actions[k2];
|
|
6742
7329
|
}
|
|
6743
7330
|
}
|
|
@@ -6747,7 +7334,7 @@
|
|
|
6747
7334
|
if (o.methods) {
|
|
6748
7335
|
var self = this;
|
|
6749
7336
|
for (var k3 in o.methods) {
|
|
6750
|
-
if (
|
|
7337
|
+
if (_hop.call(o.methods, k3)) {
|
|
6751
7338
|
this._methods[k3] = o.methods[k3];
|
|
6752
7339
|
(function (methodName, methodFn) {
|
|
6753
7340
|
self[methodName] = function () {
|
|
@@ -6765,7 +7352,7 @@
|
|
|
6765
7352
|
willMount: o.willMount || null,
|
|
6766
7353
|
mounted: o.mounted || null,
|
|
6767
7354
|
willUpdate: o.willUpdate || null,
|
|
6768
|
-
onUpdate: o.onUpdate || null,
|
|
7355
|
+
onUpdate: o.onUpdate || o.updated || null,
|
|
6769
7356
|
unmount: o.unmount || null,
|
|
6770
7357
|
willDestroy: o.willDestroy || null
|
|
6771
7358
|
};
|
|
@@ -6780,14 +7367,23 @@
|
|
|
6780
7367
|
this._compile = !!o.compile;
|
|
6781
7368
|
this._bw_refs = {};
|
|
6782
7369
|
this._refCounter = 0;
|
|
7370
|
+
// Child component ownership (Bug #5)
|
|
7371
|
+
this._children = [];
|
|
7372
|
+
this._parent = null;
|
|
7373
|
+
// Factory metadata for BCCL rebuild (Bug #6)
|
|
7374
|
+
this._factory = taco._bwFactory || null;
|
|
6783
7375
|
}
|
|
6784
7376
|
|
|
7377
|
+
// Short alias for ComponentHandle.prototype (see alias block at top of file).
|
|
7378
|
+
// 28 method definitions × 25 chars = ~700B raw savings in minified output.
|
|
7379
|
+
var _chp = ComponentHandle.prototype;
|
|
7380
|
+
|
|
6785
7381
|
// ── State Methods ──
|
|
6786
7382
|
|
|
6787
7383
|
/**
|
|
6788
7384
|
* Get a state value. Dot-path supported: `get('user.name')`
|
|
6789
7385
|
*/
|
|
6790
|
-
|
|
7386
|
+
_chp.get = function (key) {
|
|
6791
7387
|
return bw._evaluatePath(this._state, key);
|
|
6792
7388
|
};
|
|
6793
7389
|
|
|
@@ -6797,12 +7393,13 @@
|
|
|
6797
7393
|
* @param {*} value - New value
|
|
6798
7394
|
* @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
|
|
6799
7395
|
*/
|
|
6800
|
-
|
|
7396
|
+
_chp.set = function (key, value, opts) {
|
|
6801
7397
|
// Dot-path set
|
|
6802
7398
|
var parts = key.split('.');
|
|
6803
7399
|
var obj = this._state;
|
|
6804
7400
|
for (var i = 0; i < parts.length - 1; i++) {
|
|
6805
|
-
if (
|
|
7401
|
+
if (!_is(obj[parts[i]], 'object')) {
|
|
7402
|
+
if (bw.debug) _cw('bw.debug: set() — auto-creating intermediate "' + parts[i] + '" in path "' + key + '"');
|
|
6806
7403
|
obj[parts[i]] = {};
|
|
6807
7404
|
}
|
|
6808
7405
|
obj = obj[parts[i]];
|
|
@@ -6822,10 +7419,10 @@
|
|
|
6822
7419
|
/**
|
|
6823
7420
|
* Get a shallow clone of the full state.
|
|
6824
7421
|
*/
|
|
6825
|
-
|
|
7422
|
+
_chp.getState = function () {
|
|
6826
7423
|
var clone = {};
|
|
6827
7424
|
for (var k in this._state) {
|
|
6828
|
-
if (
|
|
7425
|
+
if (_hop.call(this._state, k)) {
|
|
6829
7426
|
clone[k] = this._state[k];
|
|
6830
7427
|
}
|
|
6831
7428
|
}
|
|
@@ -6837,9 +7434,9 @@
|
|
|
6837
7434
|
* @param {Object} updates - Key-value pairs to merge
|
|
6838
7435
|
* @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
|
|
6839
7436
|
*/
|
|
6840
|
-
|
|
7437
|
+
_chp.setState = function (updates, opts) {
|
|
6841
7438
|
for (var k in updates) {
|
|
6842
|
-
if (
|
|
7439
|
+
if (_hop.call(updates, k)) {
|
|
6843
7440
|
this._state[k] = updates[k];
|
|
6844
7441
|
this._dirtyKeys[k] = true;
|
|
6845
7442
|
}
|
|
@@ -6856,9 +7453,9 @@
|
|
|
6856
7453
|
/**
|
|
6857
7454
|
* Push a value onto an array in state. Clones the array.
|
|
6858
7455
|
*/
|
|
6859
|
-
|
|
7456
|
+
_chp.push = function (key, val) {
|
|
6860
7457
|
var arr = this.get(key);
|
|
6861
|
-
var newArr =
|
|
7458
|
+
var newArr = _isA(arr) ? arr.slice() : [];
|
|
6862
7459
|
newArr.push(val);
|
|
6863
7460
|
this.set(key, newArr);
|
|
6864
7461
|
};
|
|
@@ -6866,9 +7463,9 @@
|
|
|
6866
7463
|
/**
|
|
6867
7464
|
* Splice an array in state. Clones the array.
|
|
6868
7465
|
*/
|
|
6869
|
-
|
|
7466
|
+
_chp.splice = function (key, start, deleteCount) {
|
|
6870
7467
|
var arr = this.get(key);
|
|
6871
|
-
var newArr =
|
|
7468
|
+
var newArr = _isA(arr) ? arr.slice() : [];
|
|
6872
7469
|
var args = [start, deleteCount].concat(Array.prototype.slice.call(arguments, 3));
|
|
6873
7470
|
Array.prototype.splice.apply(newArr, args);
|
|
6874
7471
|
this.set(key, newArr);
|
|
@@ -6876,7 +7473,7 @@
|
|
|
6876
7473
|
|
|
6877
7474
|
// ── Scheduling ──
|
|
6878
7475
|
|
|
6879
|
-
|
|
7476
|
+
_chp._scheduleDirty = function () {
|
|
6880
7477
|
if (!this._scheduled) {
|
|
6881
7478
|
this._scheduled = true;
|
|
6882
7479
|
bw._dirtyComponents.push(this);
|
|
@@ -6891,16 +7488,16 @@
|
|
|
6891
7488
|
* Creates binding descriptors with refIds for targeted DOM updates.
|
|
6892
7489
|
* @private
|
|
6893
7490
|
*/
|
|
6894
|
-
|
|
7491
|
+
_chp._compileBindings = function () {
|
|
6895
7492
|
this._bindings = [];
|
|
6896
7493
|
this._refCounter = 0;
|
|
6897
|
-
var stateKeys =
|
|
7494
|
+
var stateKeys = _keys(this._state);
|
|
6898
7495
|
var self = this;
|
|
6899
7496
|
function walkTaco(taco, path) {
|
|
6900
|
-
if (
|
|
7497
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
6901
7498
|
|
|
6902
7499
|
// Check content for bindings
|
|
6903
|
-
if (
|
|
7500
|
+
if (_is(taco.c, 'string') && taco.c.indexOf('${') >= 0) {
|
|
6904
7501
|
var refId = 'bw_ref_' + self._refCounter++;
|
|
6905
7502
|
var parsed = bw._parseBindings(taco.c);
|
|
6906
7503
|
var deps = [];
|
|
@@ -6922,10 +7519,10 @@
|
|
|
6922
7519
|
// Check attributes for bindings
|
|
6923
7520
|
if (taco.a) {
|
|
6924
7521
|
for (var attrName in taco.a) {
|
|
6925
|
-
if (!
|
|
7522
|
+
if (!_hop.call(taco.a, attrName)) continue;
|
|
6926
7523
|
if (attrName === 'data-bw_ref') continue;
|
|
6927
7524
|
var attrVal = taco.a[attrName];
|
|
6928
|
-
if (
|
|
7525
|
+
if (_is(attrVal, 'string') && attrVal.indexOf('${') >= 0) {
|
|
6929
7526
|
var refId2 = 'bw_ref_' + self._refCounter++;
|
|
6930
7527
|
var parsed2 = bw._parseBindings(attrVal);
|
|
6931
7528
|
var deps2 = [];
|
|
@@ -6951,9 +7548,34 @@
|
|
|
6951
7548
|
}
|
|
6952
7549
|
|
|
6953
7550
|
// Recurse into children
|
|
6954
|
-
if (
|
|
7551
|
+
if (_isA(taco.c)) {
|
|
6955
7552
|
for (var i = 0; i < taco.c.length; i++) {
|
|
6956
|
-
|
|
7553
|
+
// Wrap string children with ${expr} in a span so patches target the span, not the parent
|
|
7554
|
+
if (_is(taco.c[i], 'string') && taco.c[i].indexOf('${') >= 0) {
|
|
7555
|
+
var mixedRefId = 'bw_ref_' + self._refCounter++;
|
|
7556
|
+
var mixedParsed = bw._parseBindings(taco.c[i]);
|
|
7557
|
+
var mixedDeps = [];
|
|
7558
|
+
for (var mi = 0; mi < mixedParsed.length; mi++) {
|
|
7559
|
+
mixedDeps = mixedDeps.concat(bw._extractDeps(mixedParsed[mi].expr, stateKeys));
|
|
7560
|
+
}
|
|
7561
|
+
self._bindings.push({
|
|
7562
|
+
expr: taco.c[i],
|
|
7563
|
+
type: 'content',
|
|
7564
|
+
refId: mixedRefId,
|
|
7565
|
+
deps: mixedDeps,
|
|
7566
|
+
template: taco.c[i]
|
|
7567
|
+
});
|
|
7568
|
+
// Replace string with a span wrapper so textContent targets the span only
|
|
7569
|
+
taco.c[i] = {
|
|
7570
|
+
t: 'span',
|
|
7571
|
+
a: {
|
|
7572
|
+
'data-bw_ref': mixedRefId,
|
|
7573
|
+
style: 'display:contents'
|
|
7574
|
+
},
|
|
7575
|
+
c: taco.c[i]
|
|
7576
|
+
};
|
|
7577
|
+
}
|
|
7578
|
+
if (_is(taco.c[i], 'object') && taco.c[i].t) {
|
|
6957
7579
|
walkTaco(taco.c[i], path.concat(i));
|
|
6958
7580
|
}
|
|
6959
7581
|
// Handle bw.when/bw.each markers
|
|
@@ -6988,7 +7610,7 @@
|
|
|
6988
7610
|
taco.c[i]._refId = eachRefId;
|
|
6989
7611
|
}
|
|
6990
7612
|
}
|
|
6991
|
-
} else if (
|
|
7613
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
6992
7614
|
walkTaco(taco.c, path.concat(0));
|
|
6993
7615
|
}
|
|
6994
7616
|
return taco;
|
|
@@ -7002,7 +7624,7 @@
|
|
|
7002
7624
|
* Build ref map from the live DOM after createDOM.
|
|
7003
7625
|
* @private
|
|
7004
7626
|
*/
|
|
7005
|
-
|
|
7627
|
+
_chp._collectRefs = function () {
|
|
7006
7628
|
this._bw_refs = {};
|
|
7007
7629
|
if (!this.element) return;
|
|
7008
7630
|
var els = this.element.querySelectorAll('[data-bw_ref]');
|
|
@@ -7023,7 +7645,7 @@
|
|
|
7023
7645
|
* Creates DOM, compiles bindings, registers actions, and calls lifecycle hooks.
|
|
7024
7646
|
* @param {Element} parentEl - DOM element to mount into
|
|
7025
7647
|
*/
|
|
7026
|
-
|
|
7648
|
+
_chp.mount = function (parentEl) {
|
|
7027
7649
|
// willMount hook
|
|
7028
7650
|
if (this._hooks.willMount) this._hooks.willMount(this);
|
|
7029
7651
|
|
|
@@ -7045,7 +7667,7 @@
|
|
|
7045
7667
|
// Register named actions in function registry
|
|
7046
7668
|
var self = this;
|
|
7047
7669
|
for (var actionName in this._actions) {
|
|
7048
|
-
if (
|
|
7670
|
+
if (_hop.call(this._actions, actionName)) {
|
|
7049
7671
|
var registeredName = this._bwId + '_' + actionName;
|
|
7050
7672
|
(function (aName) {
|
|
7051
7673
|
bw.funcRegister(function (evt) {
|
|
@@ -7064,6 +7686,11 @@
|
|
|
7064
7686
|
this.element = bw.createDOM(tacoForDOM);
|
|
7065
7687
|
this.element._bwComponentHandle = this;
|
|
7066
7688
|
this.element.setAttribute('data-bw_comp_id', this._bwId);
|
|
7689
|
+
|
|
7690
|
+
// Restore o.render from original TACO (stripped by _tacoForDOM)
|
|
7691
|
+
if (this.taco.o && this.taco.o.render) {
|
|
7692
|
+
this.element._bw_render = this.taco.o.render;
|
|
7693
|
+
}
|
|
7067
7694
|
if (this._userTag) {
|
|
7068
7695
|
this.element.classList.add(this._userTag);
|
|
7069
7696
|
}
|
|
@@ -7078,6 +7705,16 @@
|
|
|
7078
7705
|
this._resolveAndApplyAll();
|
|
7079
7706
|
this.mounted = true;
|
|
7080
7707
|
|
|
7708
|
+
// Scan for child ComponentHandles and link parent/child (Bug #5)
|
|
7709
|
+
var childEls = this.element.querySelectorAll('[data-bw_comp_id]');
|
|
7710
|
+
for (var ci = 0; ci < childEls.length; ci++) {
|
|
7711
|
+
var ch = childEls[ci]._bwComponentHandle;
|
|
7712
|
+
if (ch && ch !== this && !ch._parent) {
|
|
7713
|
+
ch._parent = this;
|
|
7714
|
+
this._children.push(ch);
|
|
7715
|
+
}
|
|
7716
|
+
}
|
|
7717
|
+
|
|
7081
7718
|
// mounted hook (backward compat: fn.length === 2 wraps (el, state))
|
|
7082
7719
|
if (this._hooks.mounted) {
|
|
7083
7720
|
if (this._hooks.mounted.length === 2) {
|
|
@@ -7086,15 +7723,20 @@
|
|
|
7086
7723
|
this._hooks.mounted(this);
|
|
7087
7724
|
}
|
|
7088
7725
|
}
|
|
7726
|
+
|
|
7727
|
+
// Invoke o.render on initial mount (if present)
|
|
7728
|
+
if (this.element._bw_render) {
|
|
7729
|
+
this.element._bw_render(this.element, this._state);
|
|
7730
|
+
}
|
|
7089
7731
|
};
|
|
7090
7732
|
|
|
7091
7733
|
/**
|
|
7092
7734
|
* Prepare TACO for initial render: resolve when/each markers.
|
|
7093
7735
|
* @private
|
|
7094
7736
|
*/
|
|
7095
|
-
|
|
7096
|
-
if (!
|
|
7097
|
-
if (
|
|
7737
|
+
_chp._prepareTaco = function (taco) {
|
|
7738
|
+
if (!_is(taco, 'object')) return;
|
|
7739
|
+
if (_isA(taco.c)) {
|
|
7098
7740
|
for (var i = taco.c.length - 1; i >= 0; i--) {
|
|
7099
7741
|
var child = taco.c[i];
|
|
7100
7742
|
if (child && child._bwWhen) {
|
|
@@ -7135,7 +7777,7 @@
|
|
|
7135
7777
|
var eachExprStr = child.expr.replace(/^\$\{|\}$/g, '');
|
|
7136
7778
|
var arr = bw._evaluatePath(this._state, eachExprStr);
|
|
7137
7779
|
var items = [];
|
|
7138
|
-
if (
|
|
7780
|
+
if (_isA(arr)) {
|
|
7139
7781
|
for (var j = 0; j < arr.length; j++) {
|
|
7140
7782
|
items.push(child.factory(arr[j], j));
|
|
7141
7783
|
}
|
|
@@ -7149,11 +7791,11 @@
|
|
|
7149
7791
|
c: items
|
|
7150
7792
|
};
|
|
7151
7793
|
}
|
|
7152
|
-
if (
|
|
7794
|
+
if (_is(taco.c[i], 'object') && taco.c[i].t) {
|
|
7153
7795
|
this._prepareTaco(taco.c[i]);
|
|
7154
7796
|
}
|
|
7155
7797
|
}
|
|
7156
|
-
} else if (
|
|
7798
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
7157
7799
|
this._prepareTaco(taco.c);
|
|
7158
7800
|
}
|
|
7159
7801
|
};
|
|
@@ -7162,12 +7804,12 @@
|
|
|
7162
7804
|
* Wire action name strings (in onclick etc.) to dispatch function calls.
|
|
7163
7805
|
* @private
|
|
7164
7806
|
*/
|
|
7165
|
-
|
|
7166
|
-
if (!
|
|
7807
|
+
_chp._wireActions = function (taco) {
|
|
7808
|
+
if (!_is(taco, 'object') || !taco.t) return;
|
|
7167
7809
|
if (taco.a) {
|
|
7168
7810
|
for (var key in taco.a) {
|
|
7169
|
-
if (!
|
|
7170
|
-
if (key.startsWith('on') &&
|
|
7811
|
+
if (!_hop.call(taco.a, key)) continue;
|
|
7812
|
+
if (key.startsWith('on') && _is(taco.a[key], 'string')) {
|
|
7171
7813
|
var actionName = taco.a[key];
|
|
7172
7814
|
if (actionName in this._actions) {
|
|
7173
7815
|
var registeredName = this._bwId + '_' + actionName;
|
|
@@ -7181,11 +7823,11 @@
|
|
|
7181
7823
|
}
|
|
7182
7824
|
}
|
|
7183
7825
|
}
|
|
7184
|
-
if (
|
|
7826
|
+
if (_isA(taco.c)) {
|
|
7185
7827
|
for (var i = 0; i < taco.c.length; i++) {
|
|
7186
7828
|
this._wireActions(taco.c[i]);
|
|
7187
7829
|
}
|
|
7188
|
-
} else if (
|
|
7830
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
7189
7831
|
this._wireActions(taco.c);
|
|
7190
7832
|
}
|
|
7191
7833
|
};
|
|
@@ -7194,7 +7836,7 @@
|
|
|
7194
7836
|
* Deep-clone a TACO tree, preserving _bwWhen/_bwEach markers and their factories.
|
|
7195
7837
|
* @private
|
|
7196
7838
|
*/
|
|
7197
|
-
|
|
7839
|
+
_chp._deepCloneTaco = function (taco) {
|
|
7198
7840
|
if (taco == null) return taco;
|
|
7199
7841
|
// Preserve _bwWhen / _bwEach markers (contain functions)
|
|
7200
7842
|
if (taco._bwWhen) {
|
|
@@ -7213,22 +7855,22 @@
|
|
|
7213
7855
|
_refId: taco._refId
|
|
7214
7856
|
};
|
|
7215
7857
|
}
|
|
7216
|
-
if (
|
|
7858
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
7217
7859
|
var result = {
|
|
7218
7860
|
t: taco.t
|
|
7219
7861
|
};
|
|
7220
7862
|
if (taco.a) {
|
|
7221
7863
|
result.a = {};
|
|
7222
7864
|
for (var k in taco.a) {
|
|
7223
|
-
if (
|
|
7865
|
+
if (_hop.call(taco.a, k)) result.a[k] = taco.a[k];
|
|
7224
7866
|
}
|
|
7225
7867
|
}
|
|
7226
7868
|
if (taco.c != null) {
|
|
7227
|
-
if (
|
|
7869
|
+
if (_isA(taco.c)) {
|
|
7228
7870
|
result.c = taco.c.map(function (child) {
|
|
7229
7871
|
return this._deepCloneTaco(child);
|
|
7230
7872
|
}.bind(this));
|
|
7231
|
-
} else if (
|
|
7873
|
+
} else if (_is(taco.c, 'object')) {
|
|
7232
7874
|
result.c = this._deepCloneTaco(taco.c);
|
|
7233
7875
|
} else {
|
|
7234
7876
|
result.c = taco.c;
|
|
@@ -7242,31 +7884,34 @@
|
|
|
7242
7884
|
* Create a copy of TACO suitable for createDOM (strips o to prevent double lifecycle).
|
|
7243
7885
|
* @private
|
|
7244
7886
|
*/
|
|
7245
|
-
|
|
7246
|
-
if (!
|
|
7887
|
+
_chp._tacoForDOM = function (taco) {
|
|
7888
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
7247
7889
|
var result = {
|
|
7248
7890
|
t: taco.t
|
|
7249
7891
|
};
|
|
7250
7892
|
if (taco.a) result.a = taco.a;
|
|
7251
7893
|
if (taco.c != null) {
|
|
7252
|
-
if (
|
|
7894
|
+
if (_isA(taco.c)) {
|
|
7253
7895
|
result.c = taco.c.map(function (child) {
|
|
7254
7896
|
return this._tacoForDOM(child);
|
|
7255
7897
|
}.bind(this));
|
|
7256
|
-
} else if (
|
|
7898
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
7257
7899
|
result.c = this._tacoForDOM(taco.c);
|
|
7258
7900
|
} else {
|
|
7259
7901
|
result.c = taco.c;
|
|
7260
7902
|
}
|
|
7261
7903
|
}
|
|
7262
7904
|
// Intentionally strip o (no mounted/unmount/state/render on sub-elements)
|
|
7905
|
+
if (taco.o && (taco.o.mounted || taco.o.render || taco.o.unmount)) {
|
|
7906
|
+
_cw('bw: _tacoForDOM stripped o.mounted/render/unmount from child <' + taco.t + '>. Use onclick attribute or bw.component() for child interactivity.');
|
|
7907
|
+
}
|
|
7263
7908
|
return result;
|
|
7264
7909
|
};
|
|
7265
7910
|
|
|
7266
7911
|
/**
|
|
7267
7912
|
* Unmount: remove from DOM, deactivate, preserve state for re-mount.
|
|
7268
7913
|
*/
|
|
7269
|
-
|
|
7914
|
+
_chp.unmount = function () {
|
|
7270
7915
|
if (!this.mounted) return;
|
|
7271
7916
|
|
|
7272
7917
|
// unmount hook
|
|
@@ -7300,11 +7945,22 @@
|
|
|
7300
7945
|
/**
|
|
7301
7946
|
* Destroy: unmount + clear state + unregister actions.
|
|
7302
7947
|
*/
|
|
7303
|
-
|
|
7948
|
+
_chp.destroy = function () {
|
|
7304
7949
|
// willDestroy hook
|
|
7305
7950
|
if (this._hooks.willDestroy) {
|
|
7306
7951
|
this._hooks.willDestroy(this);
|
|
7307
7952
|
}
|
|
7953
|
+
|
|
7954
|
+
// Cascade destroy to children depth-first (Bug #5)
|
|
7955
|
+
for (var ci = this._children.length - 1; ci >= 0; ci--) {
|
|
7956
|
+
this._children[ci].destroy();
|
|
7957
|
+
}
|
|
7958
|
+
this._children = [];
|
|
7959
|
+
if (this._parent) {
|
|
7960
|
+
var idx = this._parent._children.indexOf(this);
|
|
7961
|
+
if (idx >= 0) this._parent._children.splice(idx, 1);
|
|
7962
|
+
this._parent = null;
|
|
7963
|
+
}
|
|
7308
7964
|
this.unmount();
|
|
7309
7965
|
|
|
7310
7966
|
// Unregister actions from function registry
|
|
@@ -7331,12 +7987,37 @@
|
|
|
7331
7987
|
* Flush dirty state: resolve changed bindings and apply to DOM.
|
|
7332
7988
|
* @private
|
|
7333
7989
|
*/
|
|
7334
|
-
|
|
7990
|
+
_chp._flush = function () {
|
|
7335
7991
|
this._scheduled = false;
|
|
7336
|
-
var changedKeys =
|
|
7992
|
+
var changedKeys = _keys(this._dirtyKeys);
|
|
7337
7993
|
this._dirtyKeys = {};
|
|
7338
7994
|
if (changedKeys.length === 0 || !this.mounted) return;
|
|
7339
7995
|
|
|
7996
|
+
// Factory rebuild: if a BCCL factory exists and changed keys overlap factory props,
|
|
7997
|
+
// rebuild the TACO from the factory with merged state (Bug #6)
|
|
7998
|
+
if (this._factory) {
|
|
7999
|
+
var rebuildNeeded = false;
|
|
8000
|
+
for (var fi = 0; fi < changedKeys.length; fi++) {
|
|
8001
|
+
if (_hop.call(this._factory.props, changedKeys[fi])) {
|
|
8002
|
+
rebuildNeeded = true;
|
|
8003
|
+
break;
|
|
8004
|
+
}
|
|
8005
|
+
}
|
|
8006
|
+
if (rebuildNeeded) {
|
|
8007
|
+
var merged = {};
|
|
8008
|
+
for (var mk in this._factory.props) if (_hop.call(this._factory.props, mk)) merged[mk] = this._factory.props[mk];
|
|
8009
|
+
for (var sk in this._state) if (_hop.call(this._state, sk)) merged[sk] = this._state[sk];
|
|
8010
|
+
this._factory.props = merged;
|
|
8011
|
+
var newTaco = bw.make(this._factory.type, merged);
|
|
8012
|
+
newTaco._bwFactory = this._factory;
|
|
8013
|
+
this.taco = newTaco;
|
|
8014
|
+
this._originalTaco = this._deepCloneTaco(newTaco);
|
|
8015
|
+
this._render();
|
|
8016
|
+
if (this._hooks.onUpdate) this._hooks.onUpdate(this, changedKeys);
|
|
8017
|
+
return;
|
|
8018
|
+
}
|
|
8019
|
+
}
|
|
8020
|
+
|
|
7340
8021
|
// willUpdate hook
|
|
7341
8022
|
if (this._hooks.willUpdate) {
|
|
7342
8023
|
this._hooks.willUpdate(this, changedKeys);
|
|
@@ -7374,7 +8055,7 @@
|
|
|
7374
8055
|
* Returns list of patches to apply.
|
|
7375
8056
|
* @private
|
|
7376
8057
|
*/
|
|
7377
|
-
|
|
8058
|
+
_chp._resolveBindings = function (changedKeys) {
|
|
7378
8059
|
var patches = [];
|
|
7379
8060
|
for (var i = 0; i < this._bindings.length; i++) {
|
|
7380
8061
|
var b = this._bindings[i];
|
|
@@ -7410,11 +8091,14 @@
|
|
|
7410
8091
|
* Apply patches to DOM.
|
|
7411
8092
|
* @private
|
|
7412
8093
|
*/
|
|
7413
|
-
|
|
8094
|
+
_chp._applyPatches = function (patches) {
|
|
7414
8095
|
for (var i = 0; i < patches.length; i++) {
|
|
7415
8096
|
var p = patches[i];
|
|
7416
8097
|
var el = this._bw_refs[p.refId];
|
|
7417
|
-
if (!el)
|
|
8098
|
+
if (!el) {
|
|
8099
|
+
if (bw.debug) _cw('bw.debug: _applyPatches — ref "' + p.refId + '" not found in DOM');
|
|
8100
|
+
continue;
|
|
8101
|
+
}
|
|
7418
8102
|
if (p.type === 'content') {
|
|
7419
8103
|
el.textContent = p.value;
|
|
7420
8104
|
} else if (p.type === 'attribute') {
|
|
@@ -7431,7 +8115,7 @@
|
|
|
7431
8115
|
* Resolve all bindings and apply (used for initial render).
|
|
7432
8116
|
* @private
|
|
7433
8117
|
*/
|
|
7434
|
-
|
|
8118
|
+
_chp._resolveAndApplyAll = function () {
|
|
7435
8119
|
var patches = [];
|
|
7436
8120
|
for (var i = 0; i < this._bindings.length; i++) {
|
|
7437
8121
|
var b = this._bindings[i];
|
|
@@ -7453,7 +8137,7 @@
|
|
|
7453
8137
|
* Full re-render for structural changes (when/each branch switches).
|
|
7454
8138
|
* @private
|
|
7455
8139
|
*/
|
|
7456
|
-
|
|
8140
|
+
_chp._render = function () {
|
|
7457
8141
|
if (!this.element || !this.element.parentNode) return;
|
|
7458
8142
|
var parent = this.element.parentNode;
|
|
7459
8143
|
var nextSibling = this.element.nextSibling;
|
|
@@ -7492,7 +8176,7 @@
|
|
|
7492
8176
|
* @param {string} event - Event name (e.g., 'click')
|
|
7493
8177
|
* @param {Function} handler - Event handler
|
|
7494
8178
|
*/
|
|
7495
|
-
|
|
8179
|
+
_chp.on = function (event, handler) {
|
|
7496
8180
|
if (this.element) {
|
|
7497
8181
|
this.element.addEventListener(event, handler);
|
|
7498
8182
|
}
|
|
@@ -7507,7 +8191,7 @@
|
|
|
7507
8191
|
* @param {string} event - Event name
|
|
7508
8192
|
* @param {Function} handler - Handler to remove
|
|
7509
8193
|
*/
|
|
7510
|
-
|
|
8194
|
+
_chp.off = function (event, handler) {
|
|
7511
8195
|
if (this.element) {
|
|
7512
8196
|
this.element.removeEventListener(event, handler);
|
|
7513
8197
|
}
|
|
@@ -7522,7 +8206,7 @@
|
|
|
7522
8206
|
* @param {Function} handler - Handler function
|
|
7523
8207
|
* @returns {Function} Unsubscribe function
|
|
7524
8208
|
*/
|
|
7525
|
-
|
|
8209
|
+
_chp.sub = function (topic, handler) {
|
|
7526
8210
|
var unsub = bw.sub(topic, handler);
|
|
7527
8211
|
this._subs.push(unsub);
|
|
7528
8212
|
return unsub;
|
|
@@ -7533,10 +8217,10 @@
|
|
|
7533
8217
|
* @param {string} name - Action name
|
|
7534
8218
|
* @param {...*} args - Arguments passed after comp
|
|
7535
8219
|
*/
|
|
7536
|
-
|
|
8220
|
+
_chp.action = function (name) {
|
|
7537
8221
|
var fn = this._actions[name];
|
|
7538
8222
|
if (!fn) {
|
|
7539
|
-
|
|
8223
|
+
_cw('ComponentHandle.action: unknown action "' + name + '"');
|
|
7540
8224
|
return;
|
|
7541
8225
|
}
|
|
7542
8226
|
var args = [this].concat(Array.prototype.slice.call(arguments, 1));
|
|
@@ -7548,7 +8232,7 @@
|
|
|
7548
8232
|
* @param {string} sel - CSS selector
|
|
7549
8233
|
* @returns {Element|null}
|
|
7550
8234
|
*/
|
|
7551
|
-
|
|
8235
|
+
_chp.select = function (sel) {
|
|
7552
8236
|
return this.element ? this.element.querySelector(sel) : null;
|
|
7553
8237
|
};
|
|
7554
8238
|
|
|
@@ -7557,7 +8241,7 @@
|
|
|
7557
8241
|
* @param {string} sel - CSS selector
|
|
7558
8242
|
* @returns {Element[]}
|
|
7559
8243
|
*/
|
|
7560
|
-
|
|
8244
|
+
_chp.selectAll = function (sel) {
|
|
7561
8245
|
if (!this.element) return [];
|
|
7562
8246
|
return Array.prototype.slice.call(this.element.querySelectorAll(sel));
|
|
7563
8247
|
};
|
|
@@ -7568,7 +8252,7 @@
|
|
|
7568
8252
|
* @param {string} tag - User-defined identifier (e.g. 'dashboard_prod_east')
|
|
7569
8253
|
* @returns {ComponentHandle} this (for chaining)
|
|
7570
8254
|
*/
|
|
7571
|
-
|
|
8255
|
+
_chp.userTag = function (tag) {
|
|
7572
8256
|
this._userTag = tag;
|
|
7573
8257
|
if (this.element) {
|
|
7574
8258
|
this.element.classList.add(tag);
|
|
@@ -7653,7 +8337,7 @@
|
|
|
7653
8337
|
* and calls the named method. This is the bitwrench equivalent of
|
|
7654
8338
|
* Win32 SendMessage(hwnd, msg, wParam, lParam).
|
|
7655
8339
|
*
|
|
7656
|
-
* @param {string} target - Component UUID (data-bw_comp_id) or user tag (CSS class)
|
|
8340
|
+
* @param {string} target - Component UUID (bw_uuid_*), comp ID (data-bw_comp_id), or user tag (CSS class)
|
|
7657
8341
|
* @param {string} action - Method name to call on the component
|
|
7658
8342
|
* @param {*} data - Data to pass to the method
|
|
7659
8343
|
* @returns {boolean} True if message was dispatched successfully
|
|
@@ -7670,15 +8354,20 @@
|
|
|
7670
8354
|
* };
|
|
7671
8355
|
*/
|
|
7672
8356
|
bw.message = function (target, action, data) {
|
|
7673
|
-
// Try
|
|
7674
|
-
var el = bw
|
|
7675
|
-
|
|
8357
|
+
// Try bw._el() first (handles UUID class, nodeMap cache, getElementById)
|
|
8358
|
+
var el = bw._el(target);
|
|
8359
|
+
// Then try data-bw_comp_id attribute
|
|
8360
|
+
if (!el || !el._bwComponentHandle) {
|
|
8361
|
+
el = bw.$('[data-bw_comp_id="' + target + '"]')[0];
|
|
8362
|
+
}
|
|
8363
|
+
// Then try CSS class (user tag)
|
|
8364
|
+
if (!el || !el._bwComponentHandle) {
|
|
7676
8365
|
el = bw.$('.' + target)[0];
|
|
7677
8366
|
}
|
|
7678
8367
|
if (!el || !el._bwComponentHandle) return false;
|
|
7679
8368
|
var comp = el._bwComponentHandle;
|
|
7680
|
-
if (
|
|
7681
|
-
|
|
8369
|
+
if (!_is(comp[action], 'function')) {
|
|
8370
|
+
_cw('bw.message: unknown action "' + action + '" on component ' + target);
|
|
7682
8371
|
return false;
|
|
7683
8372
|
}
|
|
7684
8373
|
comp[action](data);
|
|
@@ -7686,61 +8375,24 @@
|
|
|
7686
8375
|
};
|
|
7687
8376
|
|
|
7688
8377
|
// ===================================================================================
|
|
7689
|
-
// bw.
|
|
8378
|
+
// bw.apply() / bw.parseJSONFlex() — Server-driven UI protocol
|
|
7690
8379
|
// ===================================================================================
|
|
7691
8380
|
|
|
7692
8381
|
/**
|
|
7693
8382
|
* Registry of named functions sent via register messages.
|
|
7694
|
-
* Populated by
|
|
7695
|
-
* Invoked by
|
|
8383
|
+
* Populated by bw.apply({ type: 'register', name, body }).
|
|
8384
|
+
* Invoked by bw.apply({ type: 'call', name, args }).
|
|
7696
8385
|
* @private
|
|
7697
8386
|
*/
|
|
7698
8387
|
bw._clientFunctions = {};
|
|
7699
8388
|
|
|
7700
8389
|
/**
|
|
7701
|
-
* Whether exec messages are allowed. Set by
|
|
8390
|
+
* Whether exec messages are allowed. Set by bwclient connect opts.allowExec.
|
|
7702
8391
|
* Default false — exec messages are rejected unless explicitly opted in.
|
|
7703
8392
|
* @private
|
|
7704
8393
|
*/
|
|
7705
8394
|
bw._allowExec = false;
|
|
7706
8395
|
|
|
7707
|
-
/**
|
|
7708
|
-
* Built-in client functions available via call() without registration.
|
|
7709
|
-
* @private
|
|
7710
|
-
*/
|
|
7711
|
-
bw._builtinClientFunctions = {
|
|
7712
|
-
scrollTo: function scrollTo(selector) {
|
|
7713
|
-
var el = bw._el(selector);
|
|
7714
|
-
if (el) el.scrollTop = el.scrollHeight;
|
|
7715
|
-
},
|
|
7716
|
-
focus: function focus(selector) {
|
|
7717
|
-
var el = bw._el(selector);
|
|
7718
|
-
if (el && typeof el.focus === 'function') el.focus();
|
|
7719
|
-
},
|
|
7720
|
-
download: function download(filename, content, mimeType) {
|
|
7721
|
-
if (typeof document === 'undefined') return;
|
|
7722
|
-
var blob = new Blob([content], {
|
|
7723
|
-
type: mimeType || 'text/plain'
|
|
7724
|
-
});
|
|
7725
|
-
var a = document.createElement('a');
|
|
7726
|
-
a.href = URL.createObjectURL(blob);
|
|
7727
|
-
a.download = filename;
|
|
7728
|
-
a.click();
|
|
7729
|
-
URL.revokeObjectURL(a.href);
|
|
7730
|
-
},
|
|
7731
|
-
clipboard: function clipboard(text) {
|
|
7732
|
-
if (typeof navigator !== 'undefined' && navigator.clipboard) {
|
|
7733
|
-
navigator.clipboard.writeText(text);
|
|
7734
|
-
}
|
|
7735
|
-
},
|
|
7736
|
-
redirect: function redirect(url) {
|
|
7737
|
-
if (typeof window !== 'undefined') window.location.href = url;
|
|
7738
|
-
},
|
|
7739
|
-
log: function log() {
|
|
7740
|
-
console.log.apply(console, arguments);
|
|
7741
|
-
}
|
|
7742
|
-
};
|
|
7743
|
-
|
|
7744
8396
|
/**
|
|
7745
8397
|
* Parse a bwserve protocol message string, supporting both strict JSON
|
|
7746
8398
|
* and r-prefixed relaxed JSON (single-quoted strings, trailing commas).
|
|
@@ -7755,9 +8407,9 @@
|
|
|
7755
8407
|
* @param {string} str - JSON or r-prefixed relaxed JSON string
|
|
7756
8408
|
* @returns {Object} Parsed message object
|
|
7757
8409
|
* @throws {SyntaxError} If the string is not valid JSON or relaxed JSON
|
|
7758
|
-
* @category
|
|
8410
|
+
* @category Core
|
|
7759
8411
|
*/
|
|
7760
|
-
bw.
|
|
8412
|
+
bw.parseJSONFlex = function (str) {
|
|
7761
8413
|
str = (str || '').trim();
|
|
7762
8414
|
if (str.charAt(0) !== 'r') return JSON.parse(str);
|
|
7763
8415
|
str = str.slice(1);
|
|
@@ -7835,10 +8487,10 @@
|
|
|
7835
8487
|
* append — target.appendChild(bw.createDOM(node))
|
|
7836
8488
|
* remove — bw.cleanup(target); target.remove()
|
|
7837
8489
|
* patch — bw.patch(target, content, attr)
|
|
7838
|
-
* batch — iterate ops, call
|
|
8490
|
+
* batch — iterate ops, call bw.apply for each
|
|
7839
8491
|
* message — bw.message(target, action, data)
|
|
7840
8492
|
* register — store a named function for later call()
|
|
7841
|
-
* call — invoke a registered
|
|
8493
|
+
* call — invoke a registered function
|
|
7842
8494
|
* exec — execute arbitrary JS (requires allowExec)
|
|
7843
8495
|
*
|
|
7844
8496
|
* Target resolution:
|
|
@@ -7847,9 +8499,9 @@
|
|
|
7847
8499
|
*
|
|
7848
8500
|
* @param {Object} msg - Protocol message
|
|
7849
8501
|
* @returns {boolean} true if the message was applied successfully
|
|
7850
|
-
* @category
|
|
8502
|
+
* @category Core
|
|
7851
8503
|
*/
|
|
7852
|
-
bw.
|
|
8504
|
+
bw.apply = function (msg) {
|
|
7853
8505
|
if (!msg || !msg.type) return false;
|
|
7854
8506
|
var type = msg.type;
|
|
7855
8507
|
var target = msg.target;
|
|
@@ -7870,14 +8522,14 @@
|
|
|
7870
8522
|
} else if (type === 'remove') {
|
|
7871
8523
|
var toRemove = bw._el(target);
|
|
7872
8524
|
if (!toRemove) return false;
|
|
7873
|
-
if (
|
|
8525
|
+
if (_is(bw.cleanup, 'function')) bw.cleanup(toRemove);
|
|
7874
8526
|
toRemove.remove();
|
|
7875
8527
|
return true;
|
|
7876
8528
|
} else if (type === 'batch') {
|
|
7877
|
-
if (!
|
|
8529
|
+
if (!_isA(msg.ops)) return false;
|
|
7878
8530
|
var allOk = true;
|
|
7879
8531
|
msg.ops.forEach(function (op) {
|
|
7880
|
-
if (!bw.
|
|
8532
|
+
if (!bw.apply(op)) allOk = false;
|
|
7881
8533
|
});
|
|
7882
8534
|
return allOk;
|
|
7883
8535
|
} else if (type === 'message') {
|
|
@@ -7888,24 +8540,24 @@
|
|
|
7888
8540
|
bw._clientFunctions[msg.name] = new Function('return ' + msg.body)();
|
|
7889
8541
|
return true;
|
|
7890
8542
|
} catch (e) {
|
|
7891
|
-
|
|
8543
|
+
_ce('[bw] register error:', msg.name, e);
|
|
7892
8544
|
return false;
|
|
7893
8545
|
}
|
|
7894
8546
|
} else if (type === 'call') {
|
|
7895
8547
|
if (!msg.name) return false;
|
|
7896
|
-
var fn = bw._clientFunctions[msg.name]
|
|
7897
|
-
if (
|
|
8548
|
+
var fn = bw._clientFunctions[msg.name];
|
|
8549
|
+
if (!_is(fn, 'function')) return false;
|
|
7898
8550
|
try {
|
|
7899
|
-
var args =
|
|
8551
|
+
var args = _isA(msg.args) ? msg.args : [];
|
|
7900
8552
|
fn.apply(null, args);
|
|
7901
8553
|
return true;
|
|
7902
8554
|
} catch (e) {
|
|
7903
|
-
|
|
8555
|
+
_ce('[bw] call error:', msg.name, e);
|
|
7904
8556
|
return false;
|
|
7905
8557
|
}
|
|
7906
8558
|
} else if (type === 'exec') {
|
|
7907
8559
|
if (!bw._allowExec) {
|
|
7908
|
-
|
|
8560
|
+
_cw('[bw] exec rejected: allowExec is not enabled');
|
|
7909
8561
|
return false;
|
|
7910
8562
|
}
|
|
7911
8563
|
if (!msg.code) return false;
|
|
@@ -7913,148 +8565,13 @@
|
|
|
7913
8565
|
new Function(msg.code)();
|
|
7914
8566
|
return true;
|
|
7915
8567
|
} catch (e) {
|
|
7916
|
-
|
|
8568
|
+
_ce('[bw] exec error:', e);
|
|
7917
8569
|
return false;
|
|
7918
8570
|
}
|
|
7919
8571
|
}
|
|
7920
8572
|
return false;
|
|
7921
8573
|
};
|
|
7922
8574
|
|
|
7923
|
-
/**
|
|
7924
|
-
* Connect to a bwserve SSE endpoint and apply protocol messages automatically.
|
|
7925
|
-
*
|
|
7926
|
-
* Returns a connection object with sendAction(), on(), and close() methods.
|
|
7927
|
-
*
|
|
7928
|
-
* @param {string} url - SSE endpoint URL (e.g., '/__bw/events/client-1')
|
|
7929
|
-
* @param {Object} [opts] - Connection options
|
|
7930
|
-
* @param {string} [opts.transport='sse'] - Transport type: 'sse' (default) or 'poll'
|
|
7931
|
-
* @param {number} [opts.interval=2000] - Poll interval in ms (only for 'poll' transport)
|
|
7932
|
-
* @param {string} [opts.actionUrl] - POST endpoint for actions (default: derived from url)
|
|
7933
|
-
* @param {boolean} [opts.reconnect=true] - Auto-reconnect on disconnect
|
|
7934
|
-
* @param {boolean} [opts.allowExec=false] - Enable exec message type (arbitrary JS execution)
|
|
7935
|
-
* @param {Function} [opts.onStatus] - Status callback: 'connecting'|'connected'|'disconnected'
|
|
7936
|
-
* @param {Function} [opts.onMessage] - Raw message callback (before clientApply)
|
|
7937
|
-
* @returns {Object} Connection object { sendAction, on, close, status }
|
|
7938
|
-
* @category Server
|
|
7939
|
-
*/
|
|
7940
|
-
bw.clientConnect = function (url, opts) {
|
|
7941
|
-
opts = opts || {};
|
|
7942
|
-
var transport = opts.transport || 'sse';
|
|
7943
|
-
var actionUrl = opts.actionUrl || url.replace(/\/events\//, '/action/');
|
|
7944
|
-
var reconnect = opts.reconnect !== false;
|
|
7945
|
-
var onStatus = opts.onStatus || function () {};
|
|
7946
|
-
var onMessage = opts.onMessage || null;
|
|
7947
|
-
var handlers = {};
|
|
7948
|
-
// Set the global allowExec flag from connection options
|
|
7949
|
-
bw._allowExec = !!opts.allowExec;
|
|
7950
|
-
var conn = {
|
|
7951
|
-
status: 'connecting',
|
|
7952
|
-
_es: null,
|
|
7953
|
-
_pollTimer: null
|
|
7954
|
-
};
|
|
7955
|
-
function setStatus(s) {
|
|
7956
|
-
conn.status = s;
|
|
7957
|
-
onStatus(s);
|
|
7958
|
-
}
|
|
7959
|
-
function handleMessage(data) {
|
|
7960
|
-
try {
|
|
7961
|
-
var msg = typeof data === 'string' ? bw.clientParse(data) : data;
|
|
7962
|
-
if (onMessage) onMessage(msg);
|
|
7963
|
-
if (handlers.message) handlers.message(msg);
|
|
7964
|
-
bw.clientApply(msg);
|
|
7965
|
-
} catch (e) {
|
|
7966
|
-
if (handlers.error) handlers.error(e);
|
|
7967
|
-
}
|
|
7968
|
-
}
|
|
7969
|
-
if (transport === 'sse' && typeof EventSource !== 'undefined') {
|
|
7970
|
-
setStatus('connecting');
|
|
7971
|
-
var es = new EventSource(url);
|
|
7972
|
-
conn._es = es;
|
|
7973
|
-
es.onopen = function () {
|
|
7974
|
-
setStatus('connected');
|
|
7975
|
-
if (handlers.open) handlers.open();
|
|
7976
|
-
};
|
|
7977
|
-
es.onmessage = function (e) {
|
|
7978
|
-
handleMessage(e.data);
|
|
7979
|
-
};
|
|
7980
|
-
es.onerror = function () {
|
|
7981
|
-
if (conn.status === 'connected') {
|
|
7982
|
-
setStatus('disconnected');
|
|
7983
|
-
}
|
|
7984
|
-
if (handlers.error) handlers.error(new Error('SSE connection error'));
|
|
7985
|
-
if (!reconnect) {
|
|
7986
|
-
es.close();
|
|
7987
|
-
}
|
|
7988
|
-
// EventSource auto-reconnects by default when reconnect=true
|
|
7989
|
-
};
|
|
7990
|
-
} else if (transport === 'poll') {
|
|
7991
|
-
var interval = opts.interval || 2000;
|
|
7992
|
-
setStatus('connected');
|
|
7993
|
-
conn._pollTimer = setInterval(function () {
|
|
7994
|
-
fetch(url).then(function (r) {
|
|
7995
|
-
return r.json();
|
|
7996
|
-
}).then(function (msgs) {
|
|
7997
|
-
if (Array.isArray(msgs)) {
|
|
7998
|
-
msgs.forEach(handleMessage);
|
|
7999
|
-
} else if (msgs && msgs.type) {
|
|
8000
|
-
handleMessage(msgs);
|
|
8001
|
-
}
|
|
8002
|
-
})["catch"](function (e) {
|
|
8003
|
-
if (handlers.error) handlers.error(e);
|
|
8004
|
-
});
|
|
8005
|
-
}, interval);
|
|
8006
|
-
}
|
|
8007
|
-
|
|
8008
|
-
/**
|
|
8009
|
-
* Send an action to the server via POST.
|
|
8010
|
-
* @param {string} action - Action name
|
|
8011
|
-
* @param {Object} [data] - Action payload
|
|
8012
|
-
*/
|
|
8013
|
-
conn.sendAction = function (action, data) {
|
|
8014
|
-
var body = JSON.stringify({
|
|
8015
|
-
type: 'action',
|
|
8016
|
-
action: action,
|
|
8017
|
-
data: data || {}
|
|
8018
|
-
});
|
|
8019
|
-
fetch(actionUrl, {
|
|
8020
|
-
method: 'POST',
|
|
8021
|
-
headers: {
|
|
8022
|
-
'Content-Type': 'application/json'
|
|
8023
|
-
},
|
|
8024
|
-
body: body
|
|
8025
|
-
})["catch"](function (e) {
|
|
8026
|
-
if (handlers.error) handlers.error(e);
|
|
8027
|
-
});
|
|
8028
|
-
};
|
|
8029
|
-
|
|
8030
|
-
/**
|
|
8031
|
-
* Register an event handler.
|
|
8032
|
-
* @param {string} event - 'open'|'message'|'error'|'close'
|
|
8033
|
-
* @param {Function} handler
|
|
8034
|
-
*/
|
|
8035
|
-
conn.on = function (event, handler) {
|
|
8036
|
-
handlers[event] = handler;
|
|
8037
|
-
return conn;
|
|
8038
|
-
};
|
|
8039
|
-
|
|
8040
|
-
/**
|
|
8041
|
-
* Close the connection.
|
|
8042
|
-
*/
|
|
8043
|
-
conn.close = function () {
|
|
8044
|
-
if (conn._es) {
|
|
8045
|
-
conn._es.close();
|
|
8046
|
-
conn._es = null;
|
|
8047
|
-
}
|
|
8048
|
-
if (conn._pollTimer) {
|
|
8049
|
-
clearInterval(conn._pollTimer);
|
|
8050
|
-
conn._pollTimer = null;
|
|
8051
|
-
}
|
|
8052
|
-
setStatus('disconnected');
|
|
8053
|
-
if (handlers.close) handlers.close();
|
|
8054
|
-
};
|
|
8055
|
-
return conn;
|
|
8056
|
-
};
|
|
8057
|
-
|
|
8058
8575
|
// ===================================================================================
|
|
8059
8576
|
// bw.inspect() — Debug utility
|
|
8060
8577
|
// ===================================================================================
|
|
@@ -8081,20 +8598,20 @@
|
|
|
8081
8598
|
el = target.element;
|
|
8082
8599
|
comp = target;
|
|
8083
8600
|
} else {
|
|
8084
|
-
if (
|
|
8601
|
+
if (_is(target, 'string')) {
|
|
8085
8602
|
el = bw.$(target)[0];
|
|
8086
8603
|
}
|
|
8087
8604
|
if (!el) {
|
|
8088
|
-
|
|
8605
|
+
_cw('bw.inspect: element not found');
|
|
8089
8606
|
return null;
|
|
8090
8607
|
}
|
|
8091
8608
|
comp = el._bwComponentHandle;
|
|
8092
8609
|
}
|
|
8093
8610
|
if (!comp) {
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8611
|
+
_cl('bw.inspect: no ComponentHandle on this element');
|
|
8612
|
+
_cl(' Tag:', el.tagName);
|
|
8613
|
+
_cl(' Classes:', el.className);
|
|
8614
|
+
_cl(' _bw_state:', el._bw_state || '(none)');
|
|
8098
8615
|
return null;
|
|
8099
8616
|
}
|
|
8100
8617
|
var deps = comp._bindings.reduce(function (s, b) {
|
|
@@ -8103,13 +8620,13 @@
|
|
|
8103
8620
|
return a.indexOf(v) === i;
|
|
8104
8621
|
});
|
|
8105
8622
|
console.group('Component: ' + comp._bwId);
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8623
|
+
_cl('State:', comp._state);
|
|
8624
|
+
_cl('Bindings:', comp._bindings.length, '(deps:', deps, ')');
|
|
8625
|
+
_cl('Methods:', _keys(comp._methods));
|
|
8626
|
+
_cl('Actions:', _keys(comp._actions));
|
|
8627
|
+
_cl('User tag:', comp._userTag || '(none)');
|
|
8628
|
+
_cl('Mounted:', comp.mounted);
|
|
8629
|
+
_cl('Element:', comp.element);
|
|
8113
8630
|
console.groupEnd();
|
|
8114
8631
|
return comp;
|
|
8115
8632
|
};
|
|
@@ -8132,8 +8649,8 @@
|
|
|
8132
8649
|
// Pre-extract all binding expressions
|
|
8133
8650
|
var precompiled = [];
|
|
8134
8651
|
function walkExpressions(node) {
|
|
8135
|
-
if (!
|
|
8136
|
-
if (
|
|
8652
|
+
if (!_is(node, 'object')) return;
|
|
8653
|
+
if (_is(node.c, 'string') && node.c.indexOf('${') >= 0) {
|
|
8137
8654
|
var parsed = bw._parseBindings(node.c);
|
|
8138
8655
|
for (var i = 0; i < parsed.length; i++) {
|
|
8139
8656
|
try {
|
|
@@ -8153,9 +8670,9 @@
|
|
|
8153
8670
|
}
|
|
8154
8671
|
if (node.a) {
|
|
8155
8672
|
for (var key in node.a) {
|
|
8156
|
-
if (
|
|
8673
|
+
if (_hop.call(node.a, key)) {
|
|
8157
8674
|
var v = node.a[key];
|
|
8158
|
-
if (
|
|
8675
|
+
if (_is(v, 'string') && v.indexOf('${') >= 0) {
|
|
8159
8676
|
var parsed2 = bw._parseBindings(v);
|
|
8160
8677
|
for (var j = 0; j < parsed2.length; j++) {
|
|
8161
8678
|
try {
|
|
@@ -8176,9 +8693,9 @@
|
|
|
8176
8693
|
}
|
|
8177
8694
|
}
|
|
8178
8695
|
}
|
|
8179
|
-
if (
|
|
8696
|
+
if (_isA(node.c)) {
|
|
8180
8697
|
for (var k = 0; k < node.c.length; k++) walkExpressions(node.c[k]);
|
|
8181
|
-
} else if (
|
|
8698
|
+
} else if (_is(node.c, 'object') && node.c.t) {
|
|
8182
8699
|
walkExpressions(node.c);
|
|
8183
8700
|
}
|
|
8184
8701
|
}
|
|
@@ -8189,7 +8706,7 @@
|
|
|
8189
8706
|
handle._precompiledBindings = precompiled;
|
|
8190
8707
|
if (initialState) {
|
|
8191
8708
|
for (var k in initialState) {
|
|
8192
|
-
if (
|
|
8709
|
+
if (_hop.call(initialState, k)) {
|
|
8193
8710
|
handle._state[k] = initialState[k];
|
|
8194
8711
|
}
|
|
8195
8712
|
}
|
|
@@ -8223,21 +8740,21 @@
|
|
|
8223
8740
|
minify = _options$minify === void 0 ? false : _options$minify,
|
|
8224
8741
|
_options$pretty = options.pretty,
|
|
8225
8742
|
pretty = _options$pretty === void 0 ? !minify : _options$pretty;
|
|
8226
|
-
if (
|
|
8743
|
+
if (_is(rules, 'string')) return rules;
|
|
8227
8744
|
var css = '';
|
|
8228
8745
|
var indent = pretty ? ' ' : '';
|
|
8229
8746
|
var newline = pretty ? '\n' : '';
|
|
8230
8747
|
var space = pretty ? ' ' : '';
|
|
8231
|
-
if (
|
|
8748
|
+
if (_isA(rules)) {
|
|
8232
8749
|
css = rules.map(function (rule) {
|
|
8233
8750
|
return bw.css(rule, options);
|
|
8234
8751
|
}).join(newline);
|
|
8235
|
-
} else if (
|
|
8752
|
+
} else if (_is(rules, 'object')) {
|
|
8236
8753
|
Object.entries(rules).forEach(function (_ref5) {
|
|
8237
8754
|
var _ref6 = _slicedToArray(_ref5, 2),
|
|
8238
8755
|
selector = _ref6[0],
|
|
8239
8756
|
styles = _ref6[1];
|
|
8240
|
-
if (
|
|
8757
|
+
if (_is(styles, 'object')) {
|
|
8241
8758
|
// Handle @media, @keyframes, @supports — recurse into nested block
|
|
8242
8759
|
if (selector.charAt(0) === '@') {
|
|
8243
8760
|
var inner = bw.css(styles, options);
|
|
@@ -8283,7 +8800,7 @@
|
|
|
8283
8800
|
* @returns {Element} The style element
|
|
8284
8801
|
* @category CSS & Styling
|
|
8285
8802
|
* @see bw.css
|
|
8286
|
-
* @see bw.
|
|
8803
|
+
* @see bw.loadStyles
|
|
8287
8804
|
* @example
|
|
8288
8805
|
* bw.injectCSS('.my-class { color: red; }');
|
|
8289
8806
|
* bw.injectCSS({ '.card': { padding: '1rem' } }, { id: 'card-styles' });
|
|
@@ -8291,7 +8808,7 @@
|
|
|
8291
8808
|
bw.injectCSS = function (css) {
|
|
8292
8809
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
8293
8810
|
if (!bw._isBrowser) {
|
|
8294
|
-
|
|
8811
|
+
_cw('bw.injectCSS requires a DOM environment');
|
|
8295
8812
|
return null;
|
|
8296
8813
|
}
|
|
8297
8814
|
var _options$id = options.id,
|
|
@@ -8309,7 +8826,7 @@
|
|
|
8309
8826
|
}
|
|
8310
8827
|
|
|
8311
8828
|
// Convert CSS if needed
|
|
8312
|
-
var cssStr =
|
|
8829
|
+
var cssStr = _is(css, 'string') ? css : bw.css(css, options);
|
|
8313
8830
|
|
|
8314
8831
|
// Set or append CSS
|
|
8315
8832
|
if (append && styleEl.textContent) {
|
|
@@ -8329,230 +8846,19 @@
|
|
|
8329
8846
|
* @param {...Object} styles - Style objects to merge (left-to-right)
|
|
8330
8847
|
* @returns {Object} Merged style object
|
|
8331
8848
|
* @category CSS & Styling
|
|
8332
|
-
* @see bw.u
|
|
8333
8849
|
* @example
|
|
8334
|
-
* var style = bw.s(
|
|
8850
|
+
* var style = bw.s({ display: 'flex' }, { gap: '1rem' }, { color: 'red' });
|
|
8335
8851
|
* // => { display: 'flex', gap: '1rem', color: 'red' }
|
|
8336
8852
|
*/
|
|
8337
8853
|
bw.s = function () {
|
|
8338
8854
|
var result = {};
|
|
8339
8855
|
for (var i = 0; i < arguments.length; i++) {
|
|
8340
8856
|
var arg = arguments[i];
|
|
8341
|
-
if (
|
|
8857
|
+
if (_is(arg, 'object')) Object.assign(result, arg);
|
|
8342
8858
|
}
|
|
8343
8859
|
return result;
|
|
8344
8860
|
};
|
|
8345
8861
|
|
|
8346
|
-
/**
|
|
8347
|
-
* Pre-built CSS utility objects (like Tailwind utilities, but in JS).
|
|
8348
|
-
*
|
|
8349
|
-
* Compose with `bw.s()` to build inline styles without writing raw CSS strings.
|
|
8350
|
-
* Includes flex, padding, margin, typography, color, border, and transition utilities.
|
|
8351
|
-
*
|
|
8352
|
-
* @category CSS & Styling
|
|
8353
|
-
* @see bw.s
|
|
8354
|
-
* @example
|
|
8355
|
-
* { t: 'div', a: { style: bw.s(bw.u.flex, bw.u.gap4, bw.u.p4) },
|
|
8356
|
-
* c: 'Flexbox with 1rem gap and padding' }
|
|
8357
|
-
*/
|
|
8358
|
-
bw.u = {
|
|
8359
|
-
// Display
|
|
8360
|
-
flex: {
|
|
8361
|
-
display: 'flex'
|
|
8362
|
-
},
|
|
8363
|
-
flexCol: {
|
|
8364
|
-
display: 'flex',
|
|
8365
|
-
flexDirection: 'column'
|
|
8366
|
-
},
|
|
8367
|
-
flexRow: {
|
|
8368
|
-
display: 'flex',
|
|
8369
|
-
flexDirection: 'row'
|
|
8370
|
-
},
|
|
8371
|
-
flexWrap: {
|
|
8372
|
-
display: 'flex',
|
|
8373
|
-
flexWrap: 'wrap'
|
|
8374
|
-
},
|
|
8375
|
-
block: {
|
|
8376
|
-
display: 'block'
|
|
8377
|
-
},
|
|
8378
|
-
inline: {
|
|
8379
|
-
display: 'inline'
|
|
8380
|
-
},
|
|
8381
|
-
hidden: {
|
|
8382
|
-
display: 'none'
|
|
8383
|
-
},
|
|
8384
|
-
// Flex alignment
|
|
8385
|
-
justifyCenter: {
|
|
8386
|
-
justifyContent: 'center'
|
|
8387
|
-
},
|
|
8388
|
-
justifyBetween: {
|
|
8389
|
-
justifyContent: 'space-between'
|
|
8390
|
-
},
|
|
8391
|
-
justifyEnd: {
|
|
8392
|
-
justifyContent: 'flex-end'
|
|
8393
|
-
},
|
|
8394
|
-
alignCenter: {
|
|
8395
|
-
alignItems: 'center'
|
|
8396
|
-
},
|
|
8397
|
-
alignStart: {
|
|
8398
|
-
alignItems: 'flex-start'
|
|
8399
|
-
},
|
|
8400
|
-
alignEnd: {
|
|
8401
|
-
alignItems: 'flex-end'
|
|
8402
|
-
},
|
|
8403
|
-
// Gap (0.25rem increments)
|
|
8404
|
-
gap1: {
|
|
8405
|
-
gap: '0.25rem'
|
|
8406
|
-
},
|
|
8407
|
-
gap2: {
|
|
8408
|
-
gap: '0.5rem'
|
|
8409
|
-
},
|
|
8410
|
-
gap3: {
|
|
8411
|
-
gap: '0.75rem'
|
|
8412
|
-
},
|
|
8413
|
-
gap4: {
|
|
8414
|
-
gap: '1rem'
|
|
8415
|
-
},
|
|
8416
|
-
gap6: {
|
|
8417
|
-
gap: '1.5rem'
|
|
8418
|
-
},
|
|
8419
|
-
gap8: {
|
|
8420
|
-
gap: '2rem'
|
|
8421
|
-
},
|
|
8422
|
-
// Padding
|
|
8423
|
-
p0: {
|
|
8424
|
-
padding: '0'
|
|
8425
|
-
},
|
|
8426
|
-
p1: {
|
|
8427
|
-
padding: '0.25rem'
|
|
8428
|
-
},
|
|
8429
|
-
p2: {
|
|
8430
|
-
padding: '0.5rem'
|
|
8431
|
-
},
|
|
8432
|
-
p3: {
|
|
8433
|
-
padding: '0.75rem'
|
|
8434
|
-
},
|
|
8435
|
-
p4: {
|
|
8436
|
-
padding: '1rem'
|
|
8437
|
-
},
|
|
8438
|
-
p6: {
|
|
8439
|
-
padding: '1.5rem'
|
|
8440
|
-
},
|
|
8441
|
-
p8: {
|
|
8442
|
-
padding: '2rem'
|
|
8443
|
-
},
|
|
8444
|
-
px4: {
|
|
8445
|
-
paddingLeft: '1rem',
|
|
8446
|
-
paddingRight: '1rem'
|
|
8447
|
-
},
|
|
8448
|
-
py2: {
|
|
8449
|
-
paddingTop: '0.5rem',
|
|
8450
|
-
paddingBottom: '0.5rem'
|
|
8451
|
-
},
|
|
8452
|
-
py4: {
|
|
8453
|
-
paddingTop: '1rem',
|
|
8454
|
-
paddingBottom: '1rem'
|
|
8455
|
-
},
|
|
8456
|
-
// Margin (same scale)
|
|
8457
|
-
m0: {
|
|
8458
|
-
margin: '0'
|
|
8459
|
-
},
|
|
8460
|
-
m4: {
|
|
8461
|
-
margin: '1rem'
|
|
8462
|
-
},
|
|
8463
|
-
mt2: {
|
|
8464
|
-
marginTop: '0.5rem'
|
|
8465
|
-
},
|
|
8466
|
-
mt4: {
|
|
8467
|
-
marginTop: '1rem'
|
|
8468
|
-
},
|
|
8469
|
-
mb2: {
|
|
8470
|
-
marginBottom: '0.5rem'
|
|
8471
|
-
},
|
|
8472
|
-
mb4: {
|
|
8473
|
-
marginBottom: '1rem'
|
|
8474
|
-
},
|
|
8475
|
-
mx_auto: {
|
|
8476
|
-
marginLeft: 'auto',
|
|
8477
|
-
marginRight: 'auto'
|
|
8478
|
-
},
|
|
8479
|
-
// Typography
|
|
8480
|
-
textSm: {
|
|
8481
|
-
fontSize: '0.875rem'
|
|
8482
|
-
},
|
|
8483
|
-
textBase: {
|
|
8484
|
-
fontSize: '1rem'
|
|
8485
|
-
},
|
|
8486
|
-
textLg: {
|
|
8487
|
-
fontSize: '1.125rem'
|
|
8488
|
-
},
|
|
8489
|
-
textXl: {
|
|
8490
|
-
fontSize: '1.25rem'
|
|
8491
|
-
},
|
|
8492
|
-
text2xl: {
|
|
8493
|
-
fontSize: '1.5rem'
|
|
8494
|
-
},
|
|
8495
|
-
text3xl: {
|
|
8496
|
-
fontSize: '1.875rem'
|
|
8497
|
-
},
|
|
8498
|
-
bold: {
|
|
8499
|
-
fontWeight: '700'
|
|
8500
|
-
},
|
|
8501
|
-
semibold: {
|
|
8502
|
-
fontWeight: '600'
|
|
8503
|
-
},
|
|
8504
|
-
italic: {
|
|
8505
|
-
fontStyle: 'italic'
|
|
8506
|
-
},
|
|
8507
|
-
textCenter: {
|
|
8508
|
-
textAlign: 'center'
|
|
8509
|
-
},
|
|
8510
|
-
textRight: {
|
|
8511
|
-
textAlign: 'right'
|
|
8512
|
-
},
|
|
8513
|
-
// Colors (from design tokens)
|
|
8514
|
-
bgWhite: {
|
|
8515
|
-
background: '#ffffff'
|
|
8516
|
-
},
|
|
8517
|
-
bgTeal: {
|
|
8518
|
-
background: '#006666',
|
|
8519
|
-
color: '#ffffff'
|
|
8520
|
-
},
|
|
8521
|
-
textWhite: {
|
|
8522
|
-
color: '#ffffff'
|
|
8523
|
-
},
|
|
8524
|
-
textTeal: {
|
|
8525
|
-
color: '#006666'
|
|
8526
|
-
},
|
|
8527
|
-
textMuted: {
|
|
8528
|
-
color: '#888'
|
|
8529
|
-
},
|
|
8530
|
-
// Borders
|
|
8531
|
-
rounded: {
|
|
8532
|
-
borderRadius: '0.375rem'
|
|
8533
|
-
},
|
|
8534
|
-
roundedLg: {
|
|
8535
|
-
borderRadius: '0.5rem'
|
|
8536
|
-
},
|
|
8537
|
-
roundedFull: {
|
|
8538
|
-
borderRadius: '9999px'
|
|
8539
|
-
},
|
|
8540
|
-
border: {
|
|
8541
|
-
border: '1px solid #d8d8d8'
|
|
8542
|
-
},
|
|
8543
|
-
// Sizing
|
|
8544
|
-
wFull: {
|
|
8545
|
-
width: '100%'
|
|
8546
|
-
},
|
|
8547
|
-
hFull: {
|
|
8548
|
-
height: '100%'
|
|
8549
|
-
},
|
|
8550
|
-
// Transitions
|
|
8551
|
-
transition: {
|
|
8552
|
-
transition: 'all 0.2s ease'
|
|
8553
|
-
}
|
|
8554
|
-
};
|
|
8555
|
-
|
|
8556
8862
|
/**
|
|
8557
8863
|
* Generate responsive CSS with media query breakpoints.
|
|
8558
8864
|
*
|
|
@@ -8583,7 +8889,7 @@
|
|
|
8583
8889
|
xl: '1200px'
|
|
8584
8890
|
};
|
|
8585
8891
|
var parts = [];
|
|
8586
|
-
|
|
8892
|
+
_keys(breakpoints).forEach(function (key) {
|
|
8587
8893
|
var rules = {};
|
|
8588
8894
|
if (key === 'base') {
|
|
8589
8895
|
rules[selector] = breakpoints[key];
|
|
@@ -8655,18 +8961,18 @@
|
|
|
8655
8961
|
if (!selector) return [];
|
|
8656
8962
|
|
|
8657
8963
|
// Already an array
|
|
8658
|
-
if (
|
|
8964
|
+
if (_isA(selector)) return selector;
|
|
8659
8965
|
|
|
8660
8966
|
// Single element
|
|
8661
8967
|
if (selector.nodeType) return [selector];
|
|
8662
8968
|
|
|
8663
8969
|
// NodeList or HTMLCollection
|
|
8664
|
-
if (selector.length !== undefined &&
|
|
8970
|
+
if (selector.length !== undefined && !_is(selector, 'string')) {
|
|
8665
8971
|
return Array.from(selector);
|
|
8666
8972
|
}
|
|
8667
8973
|
|
|
8668
8974
|
// CSS selector string
|
|
8669
|
-
if (
|
|
8975
|
+
if (_is(selector, 'string')) {
|
|
8670
8976
|
return Array.from(document.querySelectorAll(selector));
|
|
8671
8977
|
}
|
|
8672
8978
|
return [];
|
|
@@ -8678,111 +8984,48 @@
|
|
|
8678
8984
|
};
|
|
8679
8985
|
}
|
|
8680
8986
|
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
* Injects bitwrench's batteries-included CSS (buttons, cards, grids, forms,
|
|
8685
|
-
* alerts, badges, nav, tabs, etc.) into the document head. Call once at app startup.
|
|
8686
|
-
* Returns null in Node.js (no DOM).
|
|
8687
|
-
*
|
|
8688
|
-
* @param {Object} [options] - Style loading options
|
|
8689
|
-
* @param {boolean} [options.minify=true] - Minify the CSS output
|
|
8690
|
-
* @returns {Element|null} Style element if in browser, null in Node.js
|
|
8691
|
-
* @category CSS & Styling
|
|
8692
|
-
* @see bw.setTheme
|
|
8693
|
-
* @see bw.applyTheme
|
|
8694
|
-
* @see bw.toggleTheme
|
|
8695
|
-
* @example
|
|
8696
|
-
* bw.loadDefaultStyles(); // inject all default CSS
|
|
8697
|
-
*/
|
|
8698
|
-
bw.loadDefaultStyles = function () {
|
|
8699
|
-
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
8700
|
-
var _options$minify2 = options.minify,
|
|
8701
|
-
minify = _options$minify2 === void 0 ? true : _options$minify2,
|
|
8702
|
-
palette = options.palette;
|
|
8703
|
-
|
|
8704
|
-
// 1. Inject structural CSS (layout, sizing — never changes with theme)
|
|
8705
|
-
if (bw._isBrowser) {
|
|
8706
|
-
var structuralCSS = bw.css(getStructuralStyles());
|
|
8707
|
-
bw.injectCSS(structuralCSS, {
|
|
8708
|
-
id: 'bw_structural',
|
|
8709
|
-
append: false,
|
|
8710
|
-
minify: minify
|
|
8711
|
-
});
|
|
8712
|
-
}
|
|
8987
|
+
// =========================================================================
|
|
8988
|
+
// v2.0.18 Clean Styles API — makeStyles / applyStyles / loadStyles / etc.
|
|
8989
|
+
// =========================================================================
|
|
8713
8990
|
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
|
|
8991
|
+
/**
|
|
8992
|
+
* Convert a scope selector to a <style> element id.
|
|
8993
|
+
* @private
|
|
8994
|
+
* @param {string} [scope] - Scope selector (e.g. '#my-dashboard', '.preview')
|
|
8995
|
+
* @returns {string} Style element id (e.g. 'bw_style_my_dashboard')
|
|
8996
|
+
*/
|
|
8997
|
+
function _scopeToStyleId(scope) {
|
|
8998
|
+
if (!scope || scope === '' || scope === 'global') return 'bw_style_global';
|
|
8999
|
+
if (scope === 'reset') return 'bw_style_reset';
|
|
9000
|
+
// Strip leading # or . and convert - to _
|
|
9001
|
+
var clean = scope.replace(/^[#.]/, '').replace(/-/g, '_');
|
|
9002
|
+
return 'bw_style_' + clean;
|
|
9003
|
+
}
|
|
8721
9004
|
|
|
8722
9005
|
/**
|
|
8723
|
-
* Generate a complete
|
|
8724
|
-
*
|
|
8725
|
-
*
|
|
8726
|
-
*
|
|
8727
|
-
*
|
|
8728
|
-
*
|
|
8729
|
-
*
|
|
8730
|
-
* @param {string}
|
|
8731
|
-
* @param {
|
|
8732
|
-
* @param {string} config.primary - Primary brand color hex
|
|
8733
|
-
* @param {string} config.secondary - Secondary color hex
|
|
8734
|
-
* @param {string} [config.tertiary] - Tertiary/accent color hex (defaults to primary)
|
|
8735
|
-
* @param {string} [config.success='#198754'] - Success color hex
|
|
8736
|
-
* @param {string} [config.danger='#dc3545'] - Danger color hex
|
|
8737
|
-
* @param {string} [config.warning='#ffc107'] - Warning color hex
|
|
8738
|
-
* @param {string} [config.info='#0dcaf0'] - Info color hex
|
|
8739
|
-
* @param {string} [config.light='#f8f9fa'] - Light color hex
|
|
8740
|
-
* @param {string} [config.dark='#212529'] - Dark color hex
|
|
8741
|
-
* @param {string} [config.background] - Page background hex (default: '#ffffff' light, derived dark)
|
|
8742
|
-
* @param {string} [config.surface] - Surface/card background hex (default: '#f8f9fa' light, derived dark)
|
|
9006
|
+
* Generate a complete styles object from seed colors and layout config.
|
|
9007
|
+
* Pure function — no DOM, no state, no side effects.
|
|
9008
|
+
*
|
|
9009
|
+
* All parameters are optional. Defaults to the bitwrench default palette.
|
|
9010
|
+
*
|
|
9011
|
+
* @param {Object} [config] - Style configuration
|
|
9012
|
+
* @param {string} [config.primary='#006666'] - Primary brand color hex
|
|
9013
|
+
* @param {string} [config.secondary='#6c757d'] - Secondary color hex
|
|
9014
|
+
* @param {string} [config.tertiary] - Tertiary color hex (defaults to primary)
|
|
8743
9015
|
* @param {string} [config.spacing='normal'] - 'compact' | 'normal' | 'spacious'
|
|
8744
9016
|
* @param {string} [config.radius='md'] - 'none' | 'sm' | 'md' | 'lg' | 'pill'
|
|
8745
|
-
* @
|
|
8746
|
-
* @param {string|number} [config.typeRatio='normal'] - 'tight' | 'normal' | 'relaxed' | 'dramatic' or a number
|
|
8747
|
-
* @param {string} [config.elevation='md'] - 'flat' | 'sm' | 'md' | 'lg'
|
|
8748
|
-
* @param {string} [config.motion='standard'] - 'reduced' | 'standard' | 'expressive'
|
|
8749
|
-
* @param {number} [config.harmonize=0.20] - 0-1, semantic color hue shift toward primary
|
|
8750
|
-
* @param {boolean} [config.inject=true] - Inject into DOM (browser only)
|
|
8751
|
-
* @returns {Object} { css, palette, name, isLightPrimary, alternate: { css, palette } }
|
|
9017
|
+
* @returns {Object} { css, alternateCss, rules, alternateRules, palette, alternatePalette, isLightPrimary }
|
|
8752
9018
|
* @category CSS & Styling
|
|
8753
|
-
* @see bw.
|
|
8754
|
-
* @see bw.
|
|
8755
|
-
* @see bw.loadDefaultStyles
|
|
9019
|
+
* @see bw.applyStyles
|
|
9020
|
+
* @see bw.loadStyles
|
|
8756
9021
|
* @example
|
|
8757
|
-
*
|
|
8758
|
-
*
|
|
8759
|
-
*
|
|
8760
|
-
* secondary: '#90e0ef',
|
|
8761
|
-
* tertiary: '#00b4d8'
|
|
8762
|
-
* });
|
|
8763
|
-
*
|
|
8764
|
-
* // Apply to a container
|
|
8765
|
-
* document.getElementById('app').classList.add('ocean');
|
|
8766
|
-
*
|
|
8767
|
-
* // Toggle to alternate palette
|
|
8768
|
-
* bw.toggleTheme();
|
|
8769
|
-
*
|
|
8770
|
-
* // Generate CSS for static export (Node.js)
|
|
8771
|
-
* var result = bw.generateTheme('sunset', {
|
|
8772
|
-
* primary: '#e76f51',
|
|
8773
|
-
* secondary: '#264653',
|
|
8774
|
-
* inject: false
|
|
8775
|
-
* });
|
|
8776
|
-
* fs.writeFileSync('sunset.css', result.css + result.alternate.css);
|
|
9022
|
+
* var styles = bw.makeStyles({ primary: '#4f46e5', secondary: '#d97706' });
|
|
9023
|
+
* console.log(styles.palette.primary.base); // '#4f46e5'
|
|
9024
|
+
* // styles.css contains all themed CSS — nothing injected
|
|
8777
9025
|
*/
|
|
8778
|
-
bw.
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
}
|
|
8782
|
-
|
|
8783
|
-
// Merge with defaults; if user didn't supply tertiary, default to their primary
|
|
8784
|
-
var fullConfig = Object.assign({}, DEFAULT_PALETTE_CONFIG, config);
|
|
8785
|
-
if (!config.tertiary) fullConfig.tertiary = fullConfig.primary;
|
|
9026
|
+
bw.makeStyles = function (config) {
|
|
9027
|
+
var fullConfig = Object.assign({}, DEFAULT_PALETTE_CONFIG, config || {});
|
|
9028
|
+
if (config && !config.tertiary) fullConfig.tertiary = fullConfig.primary;
|
|
8786
9029
|
|
|
8787
9030
|
// Derive primary palette
|
|
8788
9031
|
var palette = derivePalette(fullConfig);
|
|
@@ -8790,136 +9033,211 @@
|
|
|
8790
9033
|
// Resolve layout
|
|
8791
9034
|
var layout = resolveLayout(fullConfig);
|
|
8792
9035
|
|
|
8793
|
-
// Generate primary themed CSS rules
|
|
8794
|
-
var themedRules = generateThemedCSS(
|
|
9036
|
+
// Generate primary themed CSS rules (unscoped)
|
|
9037
|
+
var themedRules = generateThemedCSS('', palette, layout);
|
|
8795
9038
|
var cssStr = bw.css(themedRules);
|
|
8796
9039
|
|
|
8797
9040
|
// Derive alternate palette (luminance-inverted)
|
|
8798
9041
|
var altConfig = deriveAlternateConfig(fullConfig);
|
|
8799
9042
|
var altPalette = derivePalette(altConfig);
|
|
8800
9043
|
|
|
8801
|
-
// Generate alternate CSS
|
|
8802
|
-
|
|
8803
|
-
var
|
|
9044
|
+
// Generate alternate CSS rules WITHOUT .bw_theme_alt prefix (raw rules)
|
|
9045
|
+
// applyStyles() wraps them appropriately based on scope
|
|
9046
|
+
var altRawRules = generateThemedCSS('', altPalette, layout);
|
|
9047
|
+
|
|
9048
|
+
// Add body-level surface overrides for the alternate palette.
|
|
9049
|
+
// When .bw_theme_alt is on <html>, ".bw_theme_alt body" correctly matches.
|
|
9050
|
+
altRawRules['body'] = {
|
|
9051
|
+
'color': altPalette.dark.base,
|
|
9052
|
+
'background-color': altPalette.surface || altPalette.light.base
|
|
9053
|
+
};
|
|
9054
|
+
var altCssStr = bw.css(altRawRules);
|
|
8804
9055
|
|
|
8805
9056
|
// Determine if primary is light-flavored
|
|
8806
9057
|
var lightPrimary = isLightPalette(fullConfig);
|
|
9058
|
+
return {
|
|
9059
|
+
css: cssStr,
|
|
9060
|
+
alternateCss: altCssStr,
|
|
9061
|
+
rules: themedRules,
|
|
9062
|
+
alternateRules: altRawRules,
|
|
9063
|
+
palette: palette,
|
|
9064
|
+
alternatePalette: altPalette,
|
|
9065
|
+
isLightPrimary: lightPrimary
|
|
9066
|
+
};
|
|
9067
|
+
};
|
|
8807
9068
|
|
|
8808
|
-
|
|
8809
|
-
|
|
8810
|
-
|
|
8811
|
-
|
|
8812
|
-
|
|
8813
|
-
|
|
8814
|
-
|
|
8815
|
-
|
|
8816
|
-
|
|
8817
|
-
|
|
8818
|
-
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
9069
|
+
/**
|
|
9070
|
+
* Inject styles into the DOM with optional scoping.
|
|
9071
|
+
*
|
|
9072
|
+
* Takes a styles object from `makeStyles()` and creates a single `<style>`
|
|
9073
|
+
* element in `<head>`. If a scope selector is provided, all CSS rules are
|
|
9074
|
+
* wrapped under that selector. Alternate CSS is wrapped under `.bw_theme_alt`.
|
|
9075
|
+
*
|
|
9076
|
+
* @param {Object} styles - Result of `bw.makeStyles()`
|
|
9077
|
+
* @param {string} [scope] - Scope selector (e.g. '#my-dashboard', '.preview'). Omit for global.
|
|
9078
|
+
* @returns {Element|null} The `<style>` element, or null in Node.js
|
|
9079
|
+
* @category CSS & Styling
|
|
9080
|
+
* @see bw.makeStyles
|
|
9081
|
+
* @see bw.loadStyles
|
|
9082
|
+
* @see bw.clearStyles
|
|
9083
|
+
* @example
|
|
9084
|
+
* var styles = bw.makeStyles({ primary: '#4f46e5' });
|
|
9085
|
+
* bw.applyStyles(styles); // global
|
|
9086
|
+
* bw.applyStyles(styles, '#my-dashboard'); // scoped
|
|
9087
|
+
*/
|
|
9088
|
+
bw.applyStyles = function (styles, scope) {
|
|
9089
|
+
if (!bw._isBrowser) return null;
|
|
9090
|
+
if (!styles || !styles.rules) {
|
|
9091
|
+
_cw('bw.applyStyles: invalid styles object');
|
|
9092
|
+
return null;
|
|
8823
9093
|
}
|
|
9094
|
+
var styleId = _scopeToStyleId(scope);
|
|
8824
9095
|
|
|
8825
|
-
//
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
|
|
8829
|
-
color: palette.primary.textOn
|
|
8830
|
-
};
|
|
8831
|
-
bw.u.textTeal = {
|
|
8832
|
-
color: palette.primary.base
|
|
8833
|
-
};
|
|
8834
|
-
bw.u.bgWhite = {
|
|
8835
|
-
background: '#ffffff'
|
|
8836
|
-
};
|
|
8837
|
-
bw.u.textWhite = {
|
|
8838
|
-
color: '#ffffff'
|
|
8839
|
-
};
|
|
9096
|
+
// Scope the primary rules if a scope is provided
|
|
9097
|
+
var primaryRules = styles.rules;
|
|
9098
|
+
if (scope) {
|
|
9099
|
+
primaryRules = scopeRulesUnder(primaryRules, scope);
|
|
8840
9100
|
}
|
|
8841
9101
|
|
|
8842
|
-
//
|
|
8843
|
-
var
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
|
|
9102
|
+
// Wrap alternate rules with .bw_theme_alt
|
|
9103
|
+
var altRules = styles.alternateRules;
|
|
9104
|
+
if (altRules) {
|
|
9105
|
+
if (scope) {
|
|
9106
|
+
// Scoped compound: #scope.bw_theme_alt .bw_card
|
|
9107
|
+
altRules = scopeRulesUnder(altRules, scope + '.bw_theme_alt');
|
|
9108
|
+
} else {
|
|
9109
|
+
// Global: .bw_theme_alt .bw_card
|
|
9110
|
+
altRules = scopeRulesUnder(altRules, '.bw_theme_alt');
|
|
8851
9111
|
}
|
|
8852
|
-
}
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
9112
|
+
}
|
|
9113
|
+
|
|
9114
|
+
// Combine primary + alternate into one CSS string
|
|
9115
|
+
var combined = bw.css(primaryRules);
|
|
9116
|
+
if (altRules) {
|
|
9117
|
+
combined += '\n' + bw.css(altRules);
|
|
9118
|
+
}
|
|
9119
|
+
return bw.injectCSS(combined, {
|
|
9120
|
+
id: styleId,
|
|
9121
|
+
append: false
|
|
9122
|
+
});
|
|
8856
9123
|
};
|
|
8857
9124
|
|
|
8858
9125
|
/**
|
|
8859
|
-
*
|
|
8860
|
-
* by adding/removing the `bw_theme_alt` class on `<html>`.
|
|
9126
|
+
* Generate and apply styles in one call. Convenience wrapper.
|
|
8861
9127
|
*
|
|
8862
|
-
*
|
|
8863
|
-
*
|
|
9128
|
+
* Equivalent to: `bw.applyStyles(bw.makeStyles(config), scope)`
|
|
9129
|
+
*
|
|
9130
|
+
* @param {Object} [config] - Style configuration (same as `makeStyles`)
|
|
9131
|
+
* @param {string} [scope] - Scope selector (same as `applyStyles`)
|
|
9132
|
+
* @returns {Element|null} The `<style>` element, or null in Node.js
|
|
8864
9133
|
* @category CSS & Styling
|
|
8865
|
-
* @see bw.
|
|
8866
|
-
* @see bw.
|
|
9134
|
+
* @see bw.makeStyles
|
|
9135
|
+
* @see bw.applyStyles
|
|
8867
9136
|
* @example
|
|
8868
|
-
* bw.
|
|
8869
|
-
* bw.
|
|
8870
|
-
* bw.
|
|
8871
|
-
*/
|
|
8872
|
-
bw.
|
|
8873
|
-
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
9137
|
+
* bw.loadStyles(); // defaults, global
|
|
9138
|
+
* bw.loadStyles({ primary: '#4f46e5' }); // custom, global
|
|
9139
|
+
* bw.loadStyles({ primary: '#4f46e5' }, '#my-dashboard'); // custom, scoped
|
|
9140
|
+
*/
|
|
9141
|
+
bw.loadStyles = function (config, scope) {
|
|
9142
|
+
// Also inject structural CSS first (only once)
|
|
9143
|
+
if (bw._isBrowser) {
|
|
9144
|
+
var existing = document.getElementById('bw_structural');
|
|
9145
|
+
if (!existing) {
|
|
9146
|
+
var structuralCSS = bw.css(getStructuralStyles());
|
|
9147
|
+
bw.injectCSS(structuralCSS, {
|
|
9148
|
+
id: 'bw_structural',
|
|
9149
|
+
append: false
|
|
9150
|
+
});
|
|
9151
|
+
}
|
|
8882
9152
|
}
|
|
8883
|
-
bw.
|
|
8884
|
-
return bw._activeThemeMode;
|
|
9153
|
+
return bw.applyStyles(bw.makeStyles(config), scope);
|
|
8885
9154
|
};
|
|
8886
9155
|
|
|
8887
9156
|
/**
|
|
8888
|
-
*
|
|
9157
|
+
* Inject the CSS reset (box-sizing, html/body font, reduced-motion).
|
|
9158
|
+
* Idempotent — if already injected, returns the existing `<style>` element.
|
|
8889
9159
|
*
|
|
9160
|
+
* @returns {Element|null} The `<style>` element, or null in Node.js
|
|
9161
|
+
* @category CSS & Styling
|
|
9162
|
+
* @see bw.loadStyles
|
|
9163
|
+
* @see bw.clearStyles
|
|
9164
|
+
* @example
|
|
9165
|
+
* bw.loadReset(); // inject once, safe to call multiple times
|
|
9166
|
+
*/
|
|
9167
|
+
bw.loadReset = function () {
|
|
9168
|
+
if (!bw._isBrowser) return null;
|
|
9169
|
+
var existing = document.getElementById('bw_style_reset');
|
|
9170
|
+
if (existing) return existing;
|
|
9171
|
+
return bw.injectCSS(bw.css(getResetStyles()), {
|
|
9172
|
+
id: 'bw_style_reset',
|
|
9173
|
+
append: false
|
|
9174
|
+
});
|
|
9175
|
+
};
|
|
9176
|
+
|
|
9177
|
+
/**
|
|
9178
|
+
* Toggle between primary and alternate palettes.
|
|
9179
|
+
*
|
|
9180
|
+
* Adds/removes the `bw_theme_alt` class on the scoping element.
|
|
9181
|
+
* Without a scope, toggles on `<html>` (global).
|
|
9182
|
+
* With a scope, toggles on the first matching element.
|
|
9183
|
+
*
|
|
9184
|
+
* @param {string} [scope] - Scope selector (e.g. '#my-dashboard'). Omit for global.
|
|
8890
9185
|
* @returns {string} Active mode after toggle: 'primary' or 'alternate'
|
|
8891
9186
|
* @category CSS & Styling
|
|
8892
|
-
* @see bw.
|
|
8893
|
-
* @see bw.
|
|
9187
|
+
* @see bw.applyStyles
|
|
9188
|
+
* @see bw.clearStyles
|
|
8894
9189
|
* @example
|
|
8895
|
-
* bw.
|
|
9190
|
+
* bw.toggleStyles(); // global toggle on <html>
|
|
9191
|
+
* bw.toggleStyles('#my-dashboard'); // scoped toggle
|
|
8896
9192
|
*/
|
|
8897
|
-
bw.
|
|
8898
|
-
|
|
8899
|
-
|
|
9193
|
+
bw.toggleStyles = function (scope) {
|
|
9194
|
+
if (!bw._isBrowser) return 'primary';
|
|
9195
|
+
var target;
|
|
9196
|
+
if (scope) {
|
|
9197
|
+
var els = bw.$(scope);
|
|
9198
|
+
target = els[0];
|
|
9199
|
+
} else {
|
|
9200
|
+
target = document.documentElement;
|
|
9201
|
+
}
|
|
9202
|
+
if (!target) return 'primary';
|
|
9203
|
+
var hasAlt = target.classList.contains('bw_theme_alt');
|
|
9204
|
+
if (hasAlt) {
|
|
9205
|
+
target.classList.remove('bw_theme_alt');
|
|
9206
|
+
return 'primary';
|
|
9207
|
+
} else {
|
|
9208
|
+
target.classList.add('bw_theme_alt');
|
|
9209
|
+
return 'alternate';
|
|
9210
|
+
}
|
|
8900
9211
|
};
|
|
8901
9212
|
|
|
8902
9213
|
/**
|
|
8903
|
-
* Remove
|
|
8904
|
-
* Use this before generating a new theme with a different name to prevent
|
|
8905
|
-
* stale CSS accumulation.
|
|
9214
|
+
* Remove injected styles for a given scope.
|
|
8906
9215
|
*
|
|
9216
|
+
* Finds the `<style>` element by id and removes it. Also removes
|
|
9217
|
+
* the `bw_theme_alt` class from the relevant element.
|
|
9218
|
+
*
|
|
9219
|
+
* @param {string} [scope] - Scope selector. Omit to remove global styles.
|
|
8907
9220
|
* @category CSS & Styling
|
|
8908
|
-
* @see bw.
|
|
9221
|
+
* @see bw.applyStyles
|
|
9222
|
+
* @see bw.loadStyles
|
|
8909
9223
|
* @example
|
|
8910
|
-
* bw.
|
|
8911
|
-
* bw.
|
|
8912
|
-
|
|
8913
|
-
|
|
8914
|
-
|
|
8915
|
-
|
|
8916
|
-
|
|
8917
|
-
|
|
8918
|
-
|
|
8919
|
-
|
|
9224
|
+
* bw.clearStyles(); // remove global styles
|
|
9225
|
+
* bw.clearStyles('#my-dashboard'); // remove scoped styles
|
|
9226
|
+
* bw.clearStyles('reset'); // remove the CSS reset
|
|
9227
|
+
*/
|
|
9228
|
+
bw.clearStyles = function (scope) {
|
|
9229
|
+
if (!bw._isBrowser) return;
|
|
9230
|
+
var styleId = _scopeToStyleId(scope);
|
|
9231
|
+
var el = document.getElementById(styleId);
|
|
9232
|
+
if (el) el.remove();
|
|
9233
|
+
|
|
9234
|
+
// Also remove bw_theme_alt from the relevant element
|
|
9235
|
+
if (scope && scope !== 'reset' && scope !== 'global') {
|
|
9236
|
+
var targets = bw.$(scope);
|
|
9237
|
+
if (targets[0]) targets[0].classList.remove('bw_theme_alt');
|
|
9238
|
+
} else if (!scope || scope === 'global') {
|
|
9239
|
+
document.documentElement.classList.remove('bw_theme_alt');
|
|
8920
9240
|
}
|
|
8921
|
-
bw._activeTheme = null;
|
|
8922
|
-
bw._activeThemeMode = 'primary';
|
|
8923
9241
|
};
|
|
8924
9242
|
|
|
8925
9243
|
// Expose color utility functions on bw namespace
|
|
@@ -9141,10 +9459,15 @@
|
|
|
9141
9459
|
* @param {Object} config - Table configuration
|
|
9142
9460
|
* @param {Array<Object>} config.data - Array of row objects to display
|
|
9143
9461
|
* @param {Array<Object>} [config.columns] - Column definitions with key, label, render
|
|
9144
|
-
* @param {string} [config.className='
|
|
9462
|
+
* @param {string} [config.className=''] - Additional CSS classes for table element
|
|
9145
9463
|
* @param {boolean} [config.sortable=true] - Enable click-to-sort headers
|
|
9146
9464
|
* @param {Function} [config.onSort] - Sort callback (column, direction)
|
|
9147
|
-
* @
|
|
9465
|
+
* @param {boolean} [config.selectable=false] - Enable row selection on click
|
|
9466
|
+
* @param {Function} [config.onRowClick] - Row click callback (row, index, event)
|
|
9467
|
+
* @param {number} [config.pageSize] - Rows per page (enables pagination when set)
|
|
9468
|
+
* @param {number} [config.currentPage=1] - Current page number (1-based)
|
|
9469
|
+
* @param {Function} [config.onPageChange] - Page change callback (newPage)
|
|
9470
|
+
* @returns {Object} TACO object for table (with optional pagination controls)
|
|
9148
9471
|
* @category Component Builders
|
|
9149
9472
|
* @see bw.makeDataTable
|
|
9150
9473
|
* @example
|
|
@@ -9156,7 +9479,12 @@
|
|
|
9156
9479
|
* columns: [
|
|
9157
9480
|
* { key: 'name', label: 'Name' },
|
|
9158
9481
|
* { key: 'age', label: 'Age' }
|
|
9159
|
-
* ]
|
|
9482
|
+
* ],
|
|
9483
|
+
* selectable: true,
|
|
9484
|
+
* onRowClick: function(row, i) { console.log('clicked', row.name); },
|
|
9485
|
+
* pageSize: 10,
|
|
9486
|
+
* currentPage: 1,
|
|
9487
|
+
* onPageChange: function(page) { console.log('page', page); }
|
|
9160
9488
|
* });
|
|
9161
9489
|
*/
|
|
9162
9490
|
bw.makeTable = function (config) {
|
|
@@ -9174,17 +9502,25 @@
|
|
|
9174
9502
|
onSort = config.onSort,
|
|
9175
9503
|
sortColumn = config.sortColumn,
|
|
9176
9504
|
_config$sortDirection = config.sortDirection,
|
|
9177
|
-
sortDirection = _config$sortDirection === void 0 ? 'asc' : _config$sortDirection
|
|
9178
|
-
|
|
9179
|
-
|
|
9505
|
+
sortDirection = _config$sortDirection === void 0 ? 'asc' : _config$sortDirection,
|
|
9506
|
+
_config$selectable = config.selectable,
|
|
9507
|
+
selectable = _config$selectable === void 0 ? false : _config$selectable,
|
|
9508
|
+
onRowClick = config.onRowClick,
|
|
9509
|
+
pageSize = config.pageSize,
|
|
9510
|
+
_config$currentPage = config.currentPage,
|
|
9511
|
+
currentPage = _config$currentPage === void 0 ? 1 : _config$currentPage,
|
|
9512
|
+
onPageChange = config.onPageChange;
|
|
9513
|
+
|
|
9514
|
+
// Build class list: always include bw_table, add striped/hover/selectable, append user className
|
|
9180
9515
|
var cls = 'bw_table';
|
|
9181
9516
|
if (striped) cls += ' bw_table_striped';
|
|
9182
|
-
if (hover) cls += ' bw_table_hover';
|
|
9517
|
+
if (hover || selectable) cls += ' bw_table_hover';
|
|
9518
|
+
if (selectable) cls += ' bw_table_selectable';
|
|
9183
9519
|
if (className) cls += ' ' + className;
|
|
9184
9520
|
cls = cls.trim();
|
|
9185
9521
|
|
|
9186
9522
|
// Auto-detect columns if not provided
|
|
9187
|
-
var cols = columns || (data.length > 0 ?
|
|
9523
|
+
var cols = columns || (data.length > 0 ? _keys(data[0]).map(function (key) {
|
|
9188
9524
|
return {
|
|
9189
9525
|
key: key,
|
|
9190
9526
|
label: key
|
|
@@ -9203,7 +9539,7 @@
|
|
|
9203
9539
|
var bVal = b[currentSortColumn];
|
|
9204
9540
|
|
|
9205
9541
|
// Handle different types
|
|
9206
|
-
if (
|
|
9542
|
+
if (_is(aVal, 'number') && _is(bVal, 'number')) {
|
|
9207
9543
|
return currentSortDirection === 'asc' ? aVal - bVal : bVal - aVal;
|
|
9208
9544
|
}
|
|
9209
9545
|
|
|
@@ -9218,6 +9554,15 @@
|
|
|
9218
9554
|
});
|
|
9219
9555
|
}
|
|
9220
9556
|
|
|
9557
|
+
// Pagination
|
|
9558
|
+
var totalRows = sortedData.length;
|
|
9559
|
+
var totalPages = pageSize ? Math.max(1, Math.ceil(totalRows / pageSize)) : 1;
|
|
9560
|
+
var page = Math.max(1, Math.min(currentPage, totalPages));
|
|
9561
|
+
if (pageSize) {
|
|
9562
|
+
var start = (page - 1) * pageSize;
|
|
9563
|
+
sortedData = sortedData.slice(start, start + pageSize);
|
|
9564
|
+
}
|
|
9565
|
+
|
|
9221
9566
|
// Create sort handler
|
|
9222
9567
|
var handleSort = function handleSort(column) {
|
|
9223
9568
|
if (!sortable) return;
|
|
@@ -9263,12 +9608,28 @@
|
|
|
9263
9608
|
}
|
|
9264
9609
|
};
|
|
9265
9610
|
|
|
9266
|
-
// Build table body
|
|
9611
|
+
// Build table body with selectable/onRowClick support
|
|
9267
9612
|
var tbody = {
|
|
9268
9613
|
t: 'tbody',
|
|
9269
|
-
c: sortedData.map(function (row) {
|
|
9614
|
+
c: sortedData.map(function (row, idx) {
|
|
9615
|
+
var globalIdx = pageSize ? (page - 1) * pageSize + idx : idx;
|
|
9616
|
+
var rowAttrs = {};
|
|
9617
|
+
if (selectable || onRowClick) {
|
|
9618
|
+
rowAttrs.style = 'cursor:pointer;';
|
|
9619
|
+
rowAttrs.onclick = function (e) {
|
|
9620
|
+
if (selectable) {
|
|
9621
|
+
// Toggle selected class on this row
|
|
9622
|
+
var tr = e.currentTarget;
|
|
9623
|
+
tr.classList.toggle('bw_table_row_selected');
|
|
9624
|
+
}
|
|
9625
|
+
if (onRowClick) {
|
|
9626
|
+
onRowClick(row, globalIdx, e);
|
|
9627
|
+
}
|
|
9628
|
+
};
|
|
9629
|
+
}
|
|
9270
9630
|
return {
|
|
9271
9631
|
t: 'tr',
|
|
9632
|
+
a: rowAttrs,
|
|
9272
9633
|
c: cols.map(function (col) {
|
|
9273
9634
|
return {
|
|
9274
9635
|
t: 'td',
|
|
@@ -9278,13 +9639,65 @@
|
|
|
9278
9639
|
};
|
|
9279
9640
|
})
|
|
9280
9641
|
};
|
|
9281
|
-
|
|
9642
|
+
var table = {
|
|
9282
9643
|
t: 'table',
|
|
9283
9644
|
a: {
|
|
9284
9645
|
"class": cls
|
|
9285
9646
|
},
|
|
9286
9647
|
c: [thead, tbody]
|
|
9287
9648
|
};
|
|
9649
|
+
|
|
9650
|
+
// If no pagination, return table directly
|
|
9651
|
+
if (!pageSize) return table;
|
|
9652
|
+
|
|
9653
|
+
// Build pagination controls
|
|
9654
|
+
var pageButtons = [];
|
|
9655
|
+
// Previous button
|
|
9656
|
+
pageButtons.push({
|
|
9657
|
+
t: 'button',
|
|
9658
|
+
a: {
|
|
9659
|
+
"class": 'bw_btn bw_btn_sm',
|
|
9660
|
+
disabled: page <= 1 ? 'disabled' : undefined,
|
|
9661
|
+
onclick: page > 1 && onPageChange ? function () {
|
|
9662
|
+
onPageChange(page - 1);
|
|
9663
|
+
} : undefined
|
|
9664
|
+
},
|
|
9665
|
+
c: 'Prev'
|
|
9666
|
+
});
|
|
9667
|
+
// Page info
|
|
9668
|
+
pageButtons.push({
|
|
9669
|
+
t: 'span',
|
|
9670
|
+
a: {
|
|
9671
|
+
style: 'margin:0 0.5rem;font-size:0.875rem;'
|
|
9672
|
+
},
|
|
9673
|
+
c: 'Page ' + page + ' of ' + totalPages
|
|
9674
|
+
});
|
|
9675
|
+
// Next button
|
|
9676
|
+
pageButtons.push({
|
|
9677
|
+
t: 'button',
|
|
9678
|
+
a: {
|
|
9679
|
+
"class": 'bw_btn bw_btn_sm',
|
|
9680
|
+
disabled: page >= totalPages ? 'disabled' : undefined,
|
|
9681
|
+
onclick: page < totalPages && onPageChange ? function () {
|
|
9682
|
+
onPageChange(page + 1);
|
|
9683
|
+
} : undefined
|
|
9684
|
+
},
|
|
9685
|
+
c: 'Next'
|
|
9686
|
+
});
|
|
9687
|
+
return {
|
|
9688
|
+
t: 'div',
|
|
9689
|
+
a: {
|
|
9690
|
+
"class": 'bw_table_paginated'
|
|
9691
|
+
},
|
|
9692
|
+
c: [table, {
|
|
9693
|
+
t: 'div',
|
|
9694
|
+
a: {
|
|
9695
|
+
"class": 'bw_table_pagination',
|
|
9696
|
+
style: 'display:flex;align-items:center;justify-content:flex-end;padding:0.5rem 0;gap:0.25rem;'
|
|
9697
|
+
},
|
|
9698
|
+
c: pageButtons
|
|
9699
|
+
}]
|
|
9700
|
+
};
|
|
9288
9701
|
};
|
|
9289
9702
|
|
|
9290
9703
|
/**
|
|
@@ -9327,7 +9740,7 @@
|
|
|
9327
9740
|
headerRow = _config$headerRow === void 0 ? true : _config$headerRow,
|
|
9328
9741
|
columns = config.columns,
|
|
9329
9742
|
rest = _objectWithoutProperties(config, _excluded);
|
|
9330
|
-
if (!
|
|
9743
|
+
if (!_isA(data) || data.length === 0) {
|
|
9331
9744
|
return bw.makeTable(_objectSpread2({
|
|
9332
9745
|
data: [],
|
|
9333
9746
|
columns: columns || []
|
|
@@ -9424,7 +9837,7 @@
|
|
|
9424
9837
|
showLabels = _config$showLabels === void 0 ? true : _config$showLabels,
|
|
9425
9838
|
_config$className2 = config.className,
|
|
9426
9839
|
className = _config$className2 === void 0 ? '' : _config$className2;
|
|
9427
|
-
if (!
|
|
9840
|
+
if (!_isA(data) || data.length === 0) {
|
|
9428
9841
|
return {
|
|
9429
9842
|
t: 'div',
|
|
9430
9843
|
a: {
|
|
@@ -9607,7 +10020,7 @@
|
|
|
9607
10020
|
bw.render = function (element, position, taco) {
|
|
9608
10021
|
var _taco$o4, _taco$o5, _taco$o6;
|
|
9609
10022
|
// Get target element
|
|
9610
|
-
var targetEl =
|
|
10023
|
+
var targetEl = _is(element, 'string') ? document.querySelector(element) : element;
|
|
9611
10024
|
if (!targetEl) {
|
|
9612
10025
|
return {
|
|
9613
10026
|
object_type: 'error',
|
|
@@ -9745,7 +10158,7 @@
|
|
|
9745
10158
|
setContent: function setContent(content) {
|
|
9746
10159
|
this._taco.c = content;
|
|
9747
10160
|
if (this.element) {
|
|
9748
|
-
if (
|
|
10161
|
+
if (_is(content, 'string')) {
|
|
9749
10162
|
this.element.textContent = content;
|
|
9750
10163
|
} else {
|
|
9751
10164
|
// Re-render for complex content
|