bitwrench 2.0.16 → 2.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -38
- package/dist/bitwrench-bccl.cjs.js +13 -9
- package/dist/bitwrench-bccl.cjs.min.js +2 -2
- package/dist/bitwrench-bccl.esm.js +13 -9
- package/dist/bitwrench-bccl.esm.min.js +2 -2
- package/dist/bitwrench-bccl.umd.js +13 -9
- package/dist/bitwrench-bccl.umd.min.js +2 -2
- package/dist/bitwrench-code-edit.cjs.js +1 -1
- package/dist/bitwrench-code-edit.cjs.min.js +1 -1
- package/dist/bitwrench-code-edit.es5.js +1 -1
- package/dist/bitwrench-code-edit.es5.min.js +1 -1
- package/dist/bitwrench-code-edit.esm.js +1 -1
- package/dist/bitwrench-code-edit.esm.min.js +1 -1
- package/dist/bitwrench-code-edit.umd.js +1 -1
- package/dist/bitwrench-code-edit.umd.min.js +1 -1
- package/dist/bitwrench-lean.cjs.js +1438 -920
- package/dist/bitwrench-lean.cjs.min.js +20 -20
- package/dist/bitwrench-lean.es5.js +1518 -1105
- package/dist/bitwrench-lean.es5.min.js +18 -18
- package/dist/bitwrench-lean.esm.js +1437 -920
- package/dist/bitwrench-lean.esm.min.js +20 -20
- package/dist/bitwrench-lean.umd.js +1438 -920
- package/dist/bitwrench-lean.umd.min.js +20 -20
- package/dist/bitwrench-util-css.cjs.js +236 -0
- package/dist/bitwrench-util-css.cjs.min.js +22 -0
- package/dist/bitwrench-util-css.es5.js +414 -0
- package/dist/bitwrench-util-css.es5.min.js +21 -0
- package/dist/bitwrench-util-css.esm.js +230 -0
- package/dist/bitwrench-util-css.esm.min.js +21 -0
- package/dist/bitwrench-util-css.umd.js +242 -0
- package/dist/bitwrench-util-css.umd.min.js +21 -0
- package/dist/bitwrench.cjs.js +1450 -928
- package/dist/bitwrench.cjs.min.js +21 -21
- package/dist/bitwrench.css +456 -132
- package/dist/bitwrench.es5.js +1563 -1140
- package/dist/bitwrench.es5.min.js +19 -19
- package/dist/bitwrench.esm.js +1450 -929
- package/dist/bitwrench.esm.min.js +21 -21
- package/dist/bitwrench.min.css +1 -1
- package/dist/bitwrench.umd.js +1450 -928
- package/dist/bitwrench.umd.min.js +21 -21
- package/dist/builds.json +178 -90
- package/dist/bwserve.cjs.js +528 -68
- package/dist/bwserve.esm.js +527 -69
- package/dist/sri.json +44 -36
- package/package.json +5 -2
- package/readme.html +136 -49
- package/src/bitwrench-bccl.js +12 -8
- package/src/bitwrench-color-utils.js +31 -9
- package/src/bitwrench-esm-entry.js +11 -0
- package/src/bitwrench-styles.js +439 -232
- package/src/bitwrench-util-css.js +229 -0
- package/src/bitwrench.js +979 -630
- package/src/bwserve/attach.js +57 -0
- package/src/bwserve/bwclient.js +141 -0
- package/src/bwserve/bwshell.js +102 -0
- package/src/bwserve/client.js +151 -1
- package/src/bwserve/index.js +139 -29
- package/src/cli/attach.js +555 -0
- package/src/cli/convert.js +2 -5
- package/src/cli/index.js +7 -0
- package/src/cli/inject.js +1 -1
- package/src/cli/layout-default.js +47 -32
- package/src/cli/serve.js +6 -2
- package/src/generate-css.js +11 -4
- package/src/vendor/html2canvas.min.js +20 -0
- package/src/version.js +3 -3
- package/src/bwserve/shell.js +0 -103
package/dist/bitwrench.es5.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
/*! bitwrench v2.0.
|
|
1
|
+
/*! bitwrench v2.0.18 | BSD-2-Clause | https://deftio.github.com/bitwrench/pages */
|
|
2
2
|
(function (global, factory) {
|
|
3
3
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
4
4
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
5
5
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bw = factory());
|
|
6
6
|
})(this, (function () { 'use strict';
|
|
7
7
|
|
|
8
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
8
9
|
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
|
-
|
|
1275
|
-
|
|
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
|
|
1276
1267
|
};
|
|
1277
|
-
rules[
|
|
1268
|
+
rules[_sx(scope, '.bw_breadcrumb_item + .bw_breadcrumb_item::before')] = {
|
|
1278
1269
|
'color': palette.secondary.base
|
|
1279
1270
|
};
|
|
1280
|
-
rules[
|
|
1271
|
+
rules[_sx(scope, '.bw_breadcrumb_item a')] = {
|
|
1272
|
+
'color': palette.primary.base,
|
|
1273
|
+
'transition': 'color ' + mo.fast + ' ' + mo.easing
|
|
1274
|
+
};
|
|
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
|
/**
|
|
@@ -5413,7 +5595,7 @@
|
|
|
5413
5595
|
if (breakpoint === 'xs') {
|
|
5414
5596
|
classes.push("bw_col_".concat(value));
|
|
5415
5597
|
} else {
|
|
5416
|
-
classes.push("bw_col_".concat(breakpoint, "
|
|
5598
|
+
classes.push("bw_col_".concat(breakpoint, "_").concat(value));
|
|
5417
5599
|
}
|
|
5418
5600
|
});
|
|
5419
5601
|
} else if (size) {
|
|
@@ -6938,12 +7120,13 @@
|
|
|
6938
7120
|
"class": "bw_page_item ".concat(currentPage <= 1 ? 'bw_disabled' : '').trim()
|
|
6939
7121
|
},
|
|
6940
7122
|
c: {
|
|
6941
|
-
t: '
|
|
7123
|
+
t: 'button',
|
|
6942
7124
|
a: {
|
|
6943
7125
|
"class": 'bw_page_link',
|
|
6944
|
-
|
|
7126
|
+
type: 'button',
|
|
6945
7127
|
onclick: handleClick(currentPage - 1),
|
|
6946
|
-
'aria-label': 'Previous'
|
|
7128
|
+
'aria-label': 'Previous',
|
|
7129
|
+
disabled: currentPage <= 1 ? true : undefined
|
|
6947
7130
|
},
|
|
6948
7131
|
c: "\u2039"
|
|
6949
7132
|
}
|
|
@@ -6958,11 +7141,12 @@
|
|
|
6958
7141
|
"class": "bw_page_item ".concat(pageNum === currentPage ? 'bw_active' : '').trim()
|
|
6959
7142
|
},
|
|
6960
7143
|
c: {
|
|
6961
|
-
t: '
|
|
7144
|
+
t: 'button',
|
|
6962
7145
|
a: {
|
|
6963
7146
|
"class": 'bw_page_link',
|
|
6964
|
-
|
|
6965
|
-
onclick: handleClick(pageNum)
|
|
7147
|
+
type: 'button',
|
|
7148
|
+
onclick: handleClick(pageNum),
|
|
7149
|
+
'aria-current': pageNum === currentPage ? 'page' : undefined
|
|
6966
7150
|
},
|
|
6967
7151
|
c: '' + pageNum
|
|
6968
7152
|
}
|
|
@@ -6977,12 +7161,13 @@
|
|
|
6977
7161
|
"class": "bw_page_item ".concat(currentPage >= pages ? 'bw_disabled' : '').trim()
|
|
6978
7162
|
},
|
|
6979
7163
|
c: {
|
|
6980
|
-
t: '
|
|
7164
|
+
t: 'button',
|
|
6981
7165
|
a: {
|
|
6982
7166
|
"class": 'bw_page_link',
|
|
6983
|
-
|
|
7167
|
+
type: 'button',
|
|
6984
7168
|
onclick: handleClick(currentPage + 1),
|
|
6985
|
-
'aria-label': 'Next'
|
|
7169
|
+
'aria-label': 'Next',
|
|
7170
|
+
disabled: currentPage >= pages ? true : undefined
|
|
6986
7171
|
},
|
|
6987
7172
|
c: "\u203A"
|
|
6988
7173
|
}
|
|
@@ -9080,7 +9265,14 @@
|
|
|
9080
9265
|
function make(type, props) {
|
|
9081
9266
|
var def = BCCL[type];
|
|
9082
9267
|
if (!def) throw new Error('bw.make: unknown component type "' + type + '". Available: ' + Object.keys(BCCL).join(', '));
|
|
9083
|
-
|
|
9268
|
+
var taco = def.make(props || {});
|
|
9269
|
+
if (taco && _typeof(taco) === 'object') {
|
|
9270
|
+
taco._bwFactory = {
|
|
9271
|
+
type: type,
|
|
9272
|
+
props: props || {}
|
|
9273
|
+
};
|
|
9274
|
+
}
|
|
9275
|
+
return taco;
|
|
9084
9276
|
}
|
|
9085
9277
|
|
|
9086
9278
|
var components = /*#__PURE__*/Object.freeze({
|
|
@@ -9193,7 +9385,7 @@
|
|
|
9193
9385
|
__monkey_patch_is_nodejs__: {
|
|
9194
9386
|
_value: 'ignore',
|
|
9195
9387
|
set: function set(x) {
|
|
9196
|
-
this._value =
|
|
9388
|
+
this._value = _is(x, 'boolean') ? x : 'ignore';
|
|
9197
9389
|
},
|
|
9198
9390
|
get: function get() {
|
|
9199
9391
|
return this._value;
|
|
@@ -9241,6 +9433,76 @@
|
|
|
9241
9433
|
configurable: true
|
|
9242
9434
|
});
|
|
9243
9435
|
|
|
9436
|
+
// ── Internal aliases ─────────────────────────────────────────────────────
|
|
9437
|
+
// Short names for frequently-used builtins and internal methods.
|
|
9438
|
+
// Same pattern as v1 (_to = bw.typeOf, etc.).
|
|
9439
|
+
//
|
|
9440
|
+
// Why: Terser can't shorten global property chains (console.warn,
|
|
9441
|
+
// Object.prototype.hasOwnProperty, Array.isArray, document.createElement)
|
|
9442
|
+
// because it can't prove they're side-effect-free. We can, so we alias
|
|
9443
|
+
// them here. Each alias saves bytes in the minified output, and the short
|
|
9444
|
+
// names also reduce visual noise in the hot paths (binding pipeline,
|
|
9445
|
+
// createDOM, etc.).
|
|
9446
|
+
//
|
|
9447
|
+
// Alias Target Sites
|
|
9448
|
+
// ───────── ────────────────────────────────────── ─────
|
|
9449
|
+
// _hop Object.prototype.hasOwnProperty 15
|
|
9450
|
+
// _isA Array.isArray 25
|
|
9451
|
+
// _keys Object.keys 7
|
|
9452
|
+
// _to bw.typeOf (type string) 26
|
|
9453
|
+
// _is type check boolean: _is(x,'string') ~50
|
|
9454
|
+
// _cw console.warn 8
|
|
9455
|
+
// _cl console.log 11
|
|
9456
|
+
// _ce console.error 4
|
|
9457
|
+
// _chp ComponentHandle.prototype 28 (defined after constructor)
|
|
9458
|
+
//
|
|
9459
|
+
// Note: document.createElement etc. are NOT aliased because they require
|
|
9460
|
+
// `this === document` and .bind() would add overhead on every call.
|
|
9461
|
+
// Console aliases use thin wrappers (not direct refs) so test monkey-
|
|
9462
|
+
// patching of console.warn/log/error continues to work.
|
|
9463
|
+
//
|
|
9464
|
+
// `typeof x` for UNDECLARED globals (window, document, process, require,
|
|
9465
|
+
// EventSource, navigator, Promise, __filename, import.meta) MUST stay as
|
|
9466
|
+
// raw `typeof` — calling _to(x) when x doesn't exist throws ReferenceError.
|
|
9467
|
+
//
|
|
9468
|
+
// ── v1 functional type helpers (kept for reference, not currently used) ──
|
|
9469
|
+
// _toa(x, type, trueVal, falseVal) — bw.typeAssign:
|
|
9470
|
+
// returns trueVal if _to(x)===type, else falseVal.
|
|
9471
|
+
// Replaces: (typeof x === 'string') ? A : B → _toa(x,'string',A,B)
|
|
9472
|
+
// _toc(x, type, trueVal, falseVal) — bw.typeConvert:
|
|
9473
|
+
// same as _toa but if trueVal/falseVal are functions, calls them with x.
|
|
9474
|
+
// Replaces: typeof x === 'string' ? fn(x) : default → _toc(x,'string',fn,default)
|
|
9475
|
+
// Uncomment if pattern frequency justifies them:
|
|
9476
|
+
// var _toa = function(x, t, y, n) { return _to(x) === t ? y : n; };
|
|
9477
|
+
// 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); };
|
|
9478
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
9479
|
+
var _hop = Object.prototype.hasOwnProperty;
|
|
9480
|
+
var _isA = Array.isArray;
|
|
9481
|
+
var _keys = Object.keys;
|
|
9482
|
+
var _to = typeOf; // imported from bitwrench-utils.js
|
|
9483
|
+
var _is = function _is(x, t) {
|
|
9484
|
+
var r = _to(x);
|
|
9485
|
+
return r === t || r.toLowerCase() === t;
|
|
9486
|
+
};
|
|
9487
|
+
// Console aliases use thin wrappers (not direct references) so that test
|
|
9488
|
+
// code can monkey-patch console.warn/log/error and the patches take effect.
|
|
9489
|
+
var _cw = function _cw() {
|
|
9490
|
+
console.warn.apply(console, arguments);
|
|
9491
|
+
};
|
|
9492
|
+
var _cl = function _cl() {
|
|
9493
|
+
console.log.apply(console, arguments);
|
|
9494
|
+
};
|
|
9495
|
+
var _ce = function _ce() {
|
|
9496
|
+
console.error.apply(console, arguments);
|
|
9497
|
+
};
|
|
9498
|
+
|
|
9499
|
+
/**
|
|
9500
|
+
* Debug flag. When true, emits console.warn for silent binding failures
|
|
9501
|
+
* (missing paths, null refs, auto-created intermediate objects).
|
|
9502
|
+
* @type {boolean}
|
|
9503
|
+
*/
|
|
9504
|
+
bw.debug = false;
|
|
9505
|
+
|
|
9244
9506
|
/**
|
|
9245
9507
|
* Lazy-resolve Node.js `fs` module.
|
|
9246
9508
|
* Tries require('fs') first (available in CJS/UMD Node.js builds),
|
|
@@ -9390,7 +9652,7 @@
|
|
|
9390
9652
|
*/
|
|
9391
9653
|
bw._el = function (id) {
|
|
9392
9654
|
// Pass-through for DOM elements
|
|
9393
|
-
if (
|
|
9655
|
+
if (!_is(id, 'string')) return id || null;
|
|
9394
9656
|
if (!id) return null;
|
|
9395
9657
|
if (!bw._isBrowser) return null;
|
|
9396
9658
|
|
|
@@ -9418,7 +9680,12 @@
|
|
|
9418
9680
|
el = document.querySelector('[data-bw_id="' + id + '"]');
|
|
9419
9681
|
}
|
|
9420
9682
|
|
|
9421
|
-
// 5.
|
|
9683
|
+
// 5. Try class-based lookup for bw_uuid_* tokens (UUID addressing)
|
|
9684
|
+
if (!el && id.indexOf('bw_uuid_') === 0) {
|
|
9685
|
+
el = document.querySelector('.' + id);
|
|
9686
|
+
}
|
|
9687
|
+
|
|
9688
|
+
// 6. Cache the result for next time
|
|
9422
9689
|
if (el) {
|
|
9423
9690
|
bw._nodeMap[id] = el;
|
|
9424
9691
|
}
|
|
@@ -9470,6 +9737,79 @@
|
|
|
9470
9737
|
}
|
|
9471
9738
|
};
|
|
9472
9739
|
|
|
9740
|
+
// ===================================================================================
|
|
9741
|
+
// bw.assignUUID() / bw.getUUID() — Explicit UUID addressing for TACO objects
|
|
9742
|
+
// ===================================================================================
|
|
9743
|
+
|
|
9744
|
+
/**
|
|
9745
|
+
* Regex to match a bw_uuid_* token in a class string.
|
|
9746
|
+
* @private
|
|
9747
|
+
*/
|
|
9748
|
+
var _UUID_RE = /\bbw_uuid_[a-z0-9_]+\b/;
|
|
9749
|
+
|
|
9750
|
+
/**
|
|
9751
|
+
* Assign a UUID to a TACO object by appending a `bw_uuid_*` token to `taco.a.class`.
|
|
9752
|
+
*
|
|
9753
|
+
* Idempotent by default — calling twice returns the same UUID. Pass `forceNew=true`
|
|
9754
|
+
* to replace an existing UUID (useful in loops where each TACO needs a unique ID).
|
|
9755
|
+
*
|
|
9756
|
+
* @param {Object} taco - A TACO object `{t, a, c, o}`
|
|
9757
|
+
* @param {boolean} [forceNew=false] - If true, replaces any existing UUID with a new one
|
|
9758
|
+
* @returns {string} The UUID string (e.g. 'bw_uuid_a1b2c3d4e5')
|
|
9759
|
+
* @category Identifiers
|
|
9760
|
+
* @example
|
|
9761
|
+
* var card = bw.makeStatCard({ value: '0', label: 'Scans' });
|
|
9762
|
+
* var uuid = bw.assignUUID(card); // 'bw_uuid_a1b2c3d4e5'
|
|
9763
|
+
* var same = bw.assignUUID(card); // same UUID (idempotent)
|
|
9764
|
+
* var diff = bw.assignUUID(card, true); // new UUID (forced)
|
|
9765
|
+
*/
|
|
9766
|
+
bw.assignUUID = function (taco, forceNew) {
|
|
9767
|
+
if (!taco || !_is(taco, 'object')) return null;
|
|
9768
|
+
|
|
9769
|
+
// Ensure taco.a exists
|
|
9770
|
+
if (!taco.a) taco.a = {};
|
|
9771
|
+
if (!_is(taco.a["class"], 'string')) taco.a["class"] = taco.a["class"] ? String(taco.a["class"]) : '';
|
|
9772
|
+
var existing = taco.a["class"].match(_UUID_RE);
|
|
9773
|
+
if (existing && !forceNew) {
|
|
9774
|
+
return existing[0];
|
|
9775
|
+
}
|
|
9776
|
+
|
|
9777
|
+
// Remove old UUID if forceNew
|
|
9778
|
+
if (existing) {
|
|
9779
|
+
taco.a["class"] = taco.a["class"].replace(_UUID_RE, '').replace(/\s+/g, ' ').trim();
|
|
9780
|
+
}
|
|
9781
|
+
var uuid = bw.uuid('uuid');
|
|
9782
|
+
taco.a["class"] = (taco.a["class"] ? taco.a["class"] + ' ' : '') + uuid;
|
|
9783
|
+
return uuid;
|
|
9784
|
+
};
|
|
9785
|
+
|
|
9786
|
+
/**
|
|
9787
|
+
* Read the UUID from a TACO object or DOM element. Pure getter, no side effects.
|
|
9788
|
+
*
|
|
9789
|
+
* @param {Object|Element} tacoOrElement - A TACO object or DOM element
|
|
9790
|
+
* @returns {string|null} The UUID string, or null if none assigned
|
|
9791
|
+
* @category Identifiers
|
|
9792
|
+
* @example
|
|
9793
|
+
* bw.getUUID(card) // 'bw_uuid_a1b2c3d4e5' (from TACO)
|
|
9794
|
+
* bw.getUUID(domEl) // 'bw_uuid_a1b2c3d4e5' (from DOM element)
|
|
9795
|
+
* bw.getUUID({t:'div'}) // null (no UUID)
|
|
9796
|
+
*/
|
|
9797
|
+
bw.getUUID = function (tacoOrElement) {
|
|
9798
|
+
if (!tacoOrElement) return null;
|
|
9799
|
+
var classStr;
|
|
9800
|
+
// DOM element: check className
|
|
9801
|
+
if (tacoOrElement.className !== undefined && tacoOrElement.tagName) {
|
|
9802
|
+
classStr = tacoOrElement.className;
|
|
9803
|
+
}
|
|
9804
|
+
// TACO object: check a.class
|
|
9805
|
+
else if (tacoOrElement.a && _is(tacoOrElement.a["class"], 'string')) {
|
|
9806
|
+
classStr = tacoOrElement.a["class"];
|
|
9807
|
+
}
|
|
9808
|
+
if (!classStr) return null;
|
|
9809
|
+
var match = classStr.match(_UUID_RE);
|
|
9810
|
+
return match ? match[0] : null;
|
|
9811
|
+
};
|
|
9812
|
+
|
|
9473
9813
|
/**
|
|
9474
9814
|
* Escape HTML special characters to prevent XSS.
|
|
9475
9815
|
*
|
|
@@ -9485,7 +9825,7 @@
|
|
|
9485
9825
|
* // => '<b>Hello</b> & "world"'
|
|
9486
9826
|
*/
|
|
9487
9827
|
bw.escapeHTML = function (str) {
|
|
9488
|
-
if (
|
|
9828
|
+
if (!_is(str, 'string')) return '';
|
|
9489
9829
|
var escapeMap = {
|
|
9490
9830
|
'&': '&',
|
|
9491
9831
|
'<': '<',
|
|
@@ -9522,6 +9862,45 @@
|
|
|
9522
9862
|
};
|
|
9523
9863
|
};
|
|
9524
9864
|
|
|
9865
|
+
/**
|
|
9866
|
+
* Hyperscript-style TACO constructor.
|
|
9867
|
+
*
|
|
9868
|
+
* A convenience helper that returns a canonical TACO object from positional
|
|
9869
|
+
* arguments. The return value is a plain object — serializable, works with
|
|
9870
|
+
* bwserve, and accepted everywhere TACO is accepted.
|
|
9871
|
+
*
|
|
9872
|
+
* @param {string} tag - HTML tag name (e.g. 'div', 'p', 'section')
|
|
9873
|
+
* @param {Object|null} [attrs] - HTML attributes object. Pass null or omit to skip.
|
|
9874
|
+
* @param {*} [content] - Content: string, number, TACO object, or array of children.
|
|
9875
|
+
* @param {Object} [options] - TACO options (state, lifecycle hooks, render fn).
|
|
9876
|
+
* @returns {Object} Plain TACO object {t, a?, c?, o?}
|
|
9877
|
+
* @category Utilities
|
|
9878
|
+
* @see bw.html
|
|
9879
|
+
* @see bw.createDOM
|
|
9880
|
+
* @see bw.DOM
|
|
9881
|
+
* @example
|
|
9882
|
+
* bw.h('div')
|
|
9883
|
+
* // => { t: 'div' }
|
|
9884
|
+
*
|
|
9885
|
+
* bw.h('p', { class: 'bw_text_muted' }, 'Hello')
|
|
9886
|
+
* // => { t: 'p', a: { class: 'bw_text_muted' }, c: 'Hello' }
|
|
9887
|
+
*
|
|
9888
|
+
* bw.h('ul', null, [
|
|
9889
|
+
* bw.h('li', null, 'one'),
|
|
9890
|
+
* bw.h('li', null, 'two')
|
|
9891
|
+
* ])
|
|
9892
|
+
* // => { t: 'ul', c: [{ t: 'li', c: 'one' }, { t: 'li', c: 'two' }] }
|
|
9893
|
+
*/
|
|
9894
|
+
bw.h = function (tag, attrs, content, options) {
|
|
9895
|
+
var taco = {
|
|
9896
|
+
t: String(tag)
|
|
9897
|
+
};
|
|
9898
|
+
if (attrs !== null && attrs !== undefined) taco.a = attrs;
|
|
9899
|
+
if (content !== undefined) taco.c = content;
|
|
9900
|
+
if (options !== undefined) taco.o = options;
|
|
9901
|
+
return taco;
|
|
9902
|
+
};
|
|
9903
|
+
|
|
9525
9904
|
/**
|
|
9526
9905
|
* Convert a TACO object (or array of TACOs) to an HTML string.
|
|
9527
9906
|
*
|
|
@@ -9562,7 +9941,7 @@
|
|
|
9562
9941
|
}
|
|
9563
9942
|
|
|
9564
9943
|
// Handle arrays of TACOs
|
|
9565
|
-
if (
|
|
9944
|
+
if (_isA(taco)) {
|
|
9566
9945
|
return taco.map(function (t) {
|
|
9567
9946
|
return bw.html(t, options);
|
|
9568
9947
|
}).join('');
|
|
@@ -9585,17 +9964,17 @@
|
|
|
9585
9964
|
if (taco && taco._bwEach && options.state) {
|
|
9586
9965
|
var eachExpr = taco.expr.replace(/^\$\{|\}$/g, '');
|
|
9587
9966
|
var arr = bw._evaluatePath(options.state, eachExpr);
|
|
9588
|
-
if (!
|
|
9967
|
+
if (!_isA(arr)) return '';
|
|
9589
9968
|
return arr.map(function (item, idx) {
|
|
9590
9969
|
return bw.html(taco.factory(item, idx), options);
|
|
9591
9970
|
}).join('');
|
|
9592
9971
|
}
|
|
9593
9972
|
|
|
9594
9973
|
// Handle primitives and non-TACO objects
|
|
9595
|
-
if (
|
|
9974
|
+
if (!_is(taco, 'object') || !taco.t) {
|
|
9596
9975
|
var str = options.raw ? String(taco) : bw.escapeHTML(String(taco));
|
|
9597
9976
|
// Resolve template bindings if state provided
|
|
9598
|
-
if (options.state &&
|
|
9977
|
+
if (options.state && _is(str, 'string') && str.indexOf('${') >= 0) {
|
|
9599
9978
|
str = bw._resolveTemplate(str, options.state, !!options.compile);
|
|
9600
9979
|
}
|
|
9601
9980
|
return str;
|
|
@@ -9620,9 +9999,17 @@
|
|
|
9620
9999
|
// Skip null, undefined, false
|
|
9621
10000
|
if (value == null || value === false) continue;
|
|
9622
10001
|
|
|
9623
|
-
//
|
|
9624
|
-
if (key.startsWith('on'))
|
|
9625
|
-
|
|
10002
|
+
// Serialize event handlers via funcRegister
|
|
10003
|
+
if (key.startsWith('on')) {
|
|
10004
|
+
if (_is(value, 'function')) {
|
|
10005
|
+
var fnId = bw.funcRegister(value);
|
|
10006
|
+
attrStr += ' ' + key + '="' + bw.funcGetDispatchStr(fnId, 'event') + '"';
|
|
10007
|
+
} else if (_is(value, 'string')) {
|
|
10008
|
+
attrStr += ' ' + key + '="' + bw.escapeHTML(value) + '"';
|
|
10009
|
+
}
|
|
10010
|
+
continue;
|
|
10011
|
+
}
|
|
10012
|
+
if (key === 'style' && _is(value, 'object')) {
|
|
9626
10013
|
// Convert style object to string
|
|
9627
10014
|
var styleStr = Object.entries(value).filter(function (_ref) {
|
|
9628
10015
|
var _ref2 = _slicedToArray(_ref, 2),
|
|
@@ -9639,7 +10026,7 @@
|
|
|
9639
10026
|
}
|
|
9640
10027
|
} else if (key === 'class') {
|
|
9641
10028
|
// Handle class as array or string
|
|
9642
|
-
var classStr =
|
|
10029
|
+
var classStr = _isA(value) ? value.filter(Boolean).join(' ') : String(value);
|
|
9643
10030
|
if (classStr) {
|
|
9644
10031
|
attrStr += " class=\"".concat(bw.escapeHTML(classStr), "\"");
|
|
9645
10032
|
}
|
|
@@ -9675,45 +10062,215 @@
|
|
|
9675
10062
|
// Process content recursively
|
|
9676
10063
|
var contentStr = content != null ? bw.html(content, options) : '';
|
|
9677
10064
|
// Resolve template bindings in content if state provided
|
|
9678
|
-
if (options.state &&
|
|
10065
|
+
if (options.state && _is(contentStr, 'string') && contentStr.indexOf('${') >= 0) {
|
|
9679
10066
|
contentStr = bw._resolveTemplate(contentStr, options.state, !!options.compile);
|
|
9680
10067
|
}
|
|
9681
10068
|
return "<".concat(tag).concat(attrStr, ">").concat(contentStr, "</").concat(tag, ">");
|
|
9682
10069
|
};
|
|
9683
10070
|
|
|
9684
10071
|
/**
|
|
9685
|
-
*
|
|
9686
|
-
*
|
|
9687
|
-
*
|
|
9688
|
-
*
|
|
9689
|
-
*
|
|
9690
|
-
*
|
|
9691
|
-
*
|
|
9692
|
-
* @param {Object} [
|
|
9693
|
-
* @
|
|
10072
|
+
* Generate a complete, self-contained HTML document from TACO content.
|
|
10073
|
+
*
|
|
10074
|
+
* Produces a full `<!DOCTYPE html>` page with configurable runtime injection,
|
|
10075
|
+
* func registry emission (so serialized event handlers work), optional theme,
|
|
10076
|
+
* and extra head elements. Designed for static site generation, offline/airgapped
|
|
10077
|
+
* use, and the "static site that isn't static" workflow.
|
|
10078
|
+
*
|
|
10079
|
+
* @param {Object} [opts={}] - Page options
|
|
10080
|
+
* @param {Object|string|Array} [opts.body=''] - Body content: TACO, string, or array
|
|
10081
|
+
* @param {string} [opts.title='bitwrench'] - Page title
|
|
10082
|
+
* @param {Object} [opts.state] - State for ${expr} resolution in bw.html()
|
|
10083
|
+
* @param {string} [opts.runtime='shim'] - Runtime level: 'inline'|'cdn'|'shim'|'none'
|
|
10084
|
+
* @param {string} [opts.css=''] - Additional CSS for <style> block
|
|
10085
|
+
* @param {string|Object} [opts.theme=null] - Theme preset name or config object
|
|
10086
|
+
* @param {Array} [opts.head=[]] - Extra TACO elements rendered into <head>
|
|
10087
|
+
* @param {string} [opts.favicon=''] - Favicon URL
|
|
10088
|
+
* @param {string} [opts.lang='en'] - HTML lang attribute
|
|
10089
|
+
* @returns {string} Complete HTML document string
|
|
9694
10090
|
* @category DOM Generation
|
|
9695
10091
|
* @see bw.html
|
|
9696
|
-
* @see bw.DOM
|
|
9697
10092
|
* @example
|
|
9698
|
-
*
|
|
9699
|
-
*
|
|
9700
|
-
*
|
|
9701
|
-
*
|
|
9702
|
-
* })
|
|
9703
|
-
* document.body.appendChild(el);
|
|
10093
|
+
* bw.htmlPage({
|
|
10094
|
+
* title: 'My App',
|
|
10095
|
+
* body: { t: 'h1', c: 'Hello World' },
|
|
10096
|
+
* runtime: 'shim'
|
|
10097
|
+
* })
|
|
9704
10098
|
*/
|
|
9705
|
-
bw.
|
|
9706
|
-
|
|
9707
|
-
|
|
9708
|
-
|
|
10099
|
+
bw.htmlPage = function (opts) {
|
|
10100
|
+
opts = opts || {};
|
|
10101
|
+
var title = opts.title || 'bitwrench';
|
|
10102
|
+
var body = opts.body || '';
|
|
10103
|
+
var state = opts.state || undefined;
|
|
10104
|
+
var runtime = opts.runtime || 'shim';
|
|
10105
|
+
var css = opts.css || '';
|
|
10106
|
+
var theme = opts.theme || null;
|
|
10107
|
+
var headExtra = opts.head || [];
|
|
10108
|
+
var favicon = opts.favicon || '';
|
|
10109
|
+
var lang = opts.lang || 'en';
|
|
10110
|
+
|
|
10111
|
+
// Snapshot funcRegistry counter before rendering
|
|
10112
|
+
var fnCounterBefore = bw._fnIDCounter;
|
|
10113
|
+
|
|
10114
|
+
// Render body content
|
|
10115
|
+
var bodyHTML = '';
|
|
10116
|
+
if (_is(body, 'string')) {
|
|
10117
|
+
bodyHTML = body;
|
|
10118
|
+
} else {
|
|
10119
|
+
var htmlOpts = {};
|
|
10120
|
+
if (state) htmlOpts.state = state;
|
|
10121
|
+
bodyHTML = bw.html(body, htmlOpts);
|
|
9709
10122
|
}
|
|
9710
10123
|
|
|
9711
|
-
//
|
|
9712
|
-
|
|
10124
|
+
// Collect functions registered during this render
|
|
10125
|
+
var fnCounterAfter = bw._fnIDCounter;
|
|
10126
|
+
var registryEntries = '';
|
|
10127
|
+
for (var i = fnCounterBefore; i < fnCounterAfter; i++) {
|
|
10128
|
+
var fnKey = 'bw_fn_' + i;
|
|
10129
|
+
if (bw._fnRegistry[fnKey]) {
|
|
10130
|
+
registryEntries += 'bw._fnRegistry[\'' + fnKey + '\']=' + bw._fnRegistry[fnKey].toString() + ';\n';
|
|
10131
|
+
}
|
|
10132
|
+
}
|
|
9713
10133
|
|
|
9714
|
-
//
|
|
9715
|
-
|
|
9716
|
-
|
|
10134
|
+
// Build runtime script for <head>
|
|
10135
|
+
var runtimeHead = '';
|
|
10136
|
+
if (runtime === 'inline') {
|
|
10137
|
+
// Read UMD bundle synchronously if in Node.js
|
|
10138
|
+
var umdSource = null;
|
|
10139
|
+
if (bw._isNode) {
|
|
10140
|
+
try {
|
|
10141
|
+
var fs = typeof require === 'function' ? require('fs') : null;
|
|
10142
|
+
var pathMod = typeof require === 'function' ? require('path') : null;
|
|
10143
|
+
if (fs && pathMod) {
|
|
10144
|
+
// Resolve dist/ relative to this source file
|
|
10145
|
+
var srcDir = '';
|
|
10146
|
+
try {
|
|
10147
|
+
srcDir = pathMod.dirname(typeof __filename !== 'undefined' ? __filename : '');
|
|
10148
|
+
} catch (e2) {/* ESM: __filename not available */}
|
|
10149
|
+
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.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.es5.js', document.baseURI).href))) {
|
|
10150
|
+
var url = typeof require === 'function' ? require('url') : null;
|
|
10151
|
+
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.es5.js', document.baseURI).href))));
|
|
10152
|
+
}
|
|
10153
|
+
if (srcDir) {
|
|
10154
|
+
var distPath = pathMod.resolve(srcDir, '../dist/bitwrench.umd.min.js');
|
|
10155
|
+
umdSource = fs.readFileSync(distPath, 'utf8');
|
|
10156
|
+
}
|
|
10157
|
+
}
|
|
10158
|
+
} catch (e) {/* fall through */}
|
|
10159
|
+
}
|
|
10160
|
+
if (umdSource) {
|
|
10161
|
+
runtimeHead = '<script>' + umdSource + '</script>';
|
|
10162
|
+
} else {
|
|
10163
|
+
// Fallback to shim in browser or if dist not available
|
|
10164
|
+
runtimeHead = '<script>' + bw._FUNC_REGISTRY_SHIM + '</script>';
|
|
10165
|
+
}
|
|
10166
|
+
} else if (runtime === 'cdn') {
|
|
10167
|
+
runtimeHead = '<script src="https://cdn.jsdelivr.net/npm/bitwrench@2/dist/bitwrench.umd.min.js"></script>';
|
|
10168
|
+
} else if (runtime === 'shim') {
|
|
10169
|
+
runtimeHead = '<script>' + bw._FUNC_REGISTRY_SHIM + '</script>';
|
|
10170
|
+
}
|
|
10171
|
+
// runtime === 'none' → empty
|
|
10172
|
+
|
|
10173
|
+
// Theme CSS
|
|
10174
|
+
var themeCSS = '';
|
|
10175
|
+
if (theme) {
|
|
10176
|
+
var themeConfig = _is(theme, 'string') ? THEME_PRESETS[theme.toLowerCase()] || null : theme;
|
|
10177
|
+
if (themeConfig) {
|
|
10178
|
+
var themeResult = bw.makeStyles(themeConfig);
|
|
10179
|
+
themeCSS = themeResult.css;
|
|
10180
|
+
}
|
|
10181
|
+
}
|
|
10182
|
+
|
|
10183
|
+
// Extra <head> elements
|
|
10184
|
+
var headHTML = '';
|
|
10185
|
+
if (_isA(headExtra) && headExtra.length > 0) {
|
|
10186
|
+
headHTML = headExtra.map(function (el) {
|
|
10187
|
+
return bw.html(el);
|
|
10188
|
+
}).join('\n');
|
|
10189
|
+
}
|
|
10190
|
+
|
|
10191
|
+
// Favicon
|
|
10192
|
+
var faviconTag = '';
|
|
10193
|
+
if (favicon) {
|
|
10194
|
+
var safeFavicon = favicon.replace(/[&<>"']/g, function (c) {
|
|
10195
|
+
return {
|
|
10196
|
+
'&': '&',
|
|
10197
|
+
'<': '<',
|
|
10198
|
+
'>': '>',
|
|
10199
|
+
'"': '"',
|
|
10200
|
+
"'": '''
|
|
10201
|
+
}[c];
|
|
10202
|
+
});
|
|
10203
|
+
faviconTag = '<link rel="icon" href="' + safeFavicon + '">';
|
|
10204
|
+
}
|
|
10205
|
+
|
|
10206
|
+
// Escaped title
|
|
10207
|
+
var safeTitle = bw.escapeHTML(title);
|
|
10208
|
+
|
|
10209
|
+
// Combine all CSS
|
|
10210
|
+
var allCSS = (themeCSS ? themeCSS + '\n' : '') + css;
|
|
10211
|
+
|
|
10212
|
+
// Body-end script: registry entries + optional loadStyles
|
|
10213
|
+
var bodyEndScript = '';
|
|
10214
|
+
var bodyEndParts = [];
|
|
10215
|
+
if (registryEntries) {
|
|
10216
|
+
bodyEndParts.push(registryEntries);
|
|
10217
|
+
}
|
|
10218
|
+
if (runtime === 'inline' || runtime === 'cdn') {
|
|
10219
|
+
bodyEndParts.push('if(typeof bw!=="undefined"){bw.loadStyles();}');
|
|
10220
|
+
}
|
|
10221
|
+
if (bodyEndParts.length > 0) {
|
|
10222
|
+
bodyEndScript = '<script>\n' + bodyEndParts.join('\n') + '\n</script>';
|
|
10223
|
+
}
|
|
10224
|
+
|
|
10225
|
+
// Assemble document
|
|
10226
|
+
var parts = ['<!DOCTYPE html>', '<html lang="' + lang + '">', '<head>', '<meta charset="UTF-8">', '<meta name="viewport" content="width=device-width, initial-scale=1">'];
|
|
10227
|
+
parts.push('<title>' + safeTitle + '</title>');
|
|
10228
|
+
if (faviconTag) parts.push(faviconTag);
|
|
10229
|
+
if (runtimeHead) parts.push(runtimeHead);
|
|
10230
|
+
if (headHTML) parts.push(headHTML);
|
|
10231
|
+
if (allCSS) parts.push('<style>' + allCSS + '</style>');
|
|
10232
|
+
parts.push('</head>');
|
|
10233
|
+
parts.push('<body>');
|
|
10234
|
+
parts.push(bodyHTML);
|
|
10235
|
+
if (bodyEndScript) parts.push(bodyEndScript);
|
|
10236
|
+
parts.push('</body>');
|
|
10237
|
+
parts.push('</html>');
|
|
10238
|
+
return parts.join('\n');
|
|
10239
|
+
};
|
|
10240
|
+
|
|
10241
|
+
/**
|
|
10242
|
+
* Create a live DOM element from a TACO object (browser only).
|
|
10243
|
+
*
|
|
10244
|
+
* Unlike `bw.html()` which returns a string, this creates real DOM elements
|
|
10245
|
+
* with event handlers, lifecycle hooks (mounted/unmount), and state. Used
|
|
10246
|
+
* internally by `bw.DOM()`. Throws in Node.js — use `bw.html()` instead.
|
|
10247
|
+
*
|
|
10248
|
+
* @param {Object} taco - TACO object with {t, a, c, o}
|
|
10249
|
+
* @param {Object} [options] - Creation options
|
|
10250
|
+
* @returns {Element|Text} DOM element or text node
|
|
10251
|
+
* @category DOM Generation
|
|
10252
|
+
* @see bw.html
|
|
10253
|
+
* @see bw.DOM
|
|
10254
|
+
* @example
|
|
10255
|
+
* var el = bw.createDOM({
|
|
10256
|
+
* t: 'button',
|
|
10257
|
+
* a: { class: 'bw_btn', onclick: () => alert('clicked') },
|
|
10258
|
+
* c: 'Click Me'
|
|
10259
|
+
* });
|
|
10260
|
+
* document.body.appendChild(el);
|
|
10261
|
+
*/
|
|
10262
|
+
bw.createDOM = function (taco) {
|
|
10263
|
+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
10264
|
+
if (!bw._isBrowser) {
|
|
10265
|
+
throw new Error('bw.createDOM requires a DOM environment (document/window). Use bw.html() instead.');
|
|
10266
|
+
}
|
|
10267
|
+
|
|
10268
|
+
// Handle null/undefined
|
|
10269
|
+
if (taco == null) return document.createTextNode('');
|
|
10270
|
+
|
|
10271
|
+
// Handle bw.raw() marked content — inject as HTML
|
|
10272
|
+
if (taco && taco.__bw_raw) {
|
|
10273
|
+
var frag = document.createDocumentFragment();
|
|
9717
10274
|
var tmp = document.createElement('span');
|
|
9718
10275
|
tmp.innerHTML = taco.v;
|
|
9719
10276
|
while (tmp.firstChild) frag.appendChild(tmp.firstChild);
|
|
@@ -9726,7 +10283,7 @@
|
|
|
9726
10283
|
}
|
|
9727
10284
|
|
|
9728
10285
|
// Handle text nodes
|
|
9729
|
-
if (
|
|
10286
|
+
if (!_is(taco, 'object') || !taco.t) {
|
|
9730
10287
|
return document.createTextNode(String(taco));
|
|
9731
10288
|
}
|
|
9732
10289
|
var tag = taco.t,
|
|
@@ -9745,16 +10302,16 @@
|
|
|
9745
10302
|
key = _Object$entries2$_i[0],
|
|
9746
10303
|
value = _Object$entries2$_i[1];
|
|
9747
10304
|
if (value == null || value === false) continue;
|
|
9748
|
-
if (key === 'style' &&
|
|
10305
|
+
if (key === 'style' && _is(value, 'object')) {
|
|
9749
10306
|
// Apply styles directly
|
|
9750
10307
|
Object.assign(el.style, value);
|
|
9751
10308
|
} else if (key === 'class') {
|
|
9752
10309
|
// Handle class as array or string
|
|
9753
|
-
var classStr =
|
|
10310
|
+
var classStr = _isA(value) ? value.filter(Boolean).join(' ') : String(value);
|
|
9754
10311
|
if (classStr) {
|
|
9755
10312
|
el.className = classStr;
|
|
9756
10313
|
}
|
|
9757
|
-
} else if (key.startsWith('on') &&
|
|
10314
|
+
} else if (key.startsWith('on') && _is(value, 'function')) {
|
|
9758
10315
|
// Event handlers
|
|
9759
10316
|
var eventName = key.slice(2).toLowerCase();
|
|
9760
10317
|
el.addEventListener(eventName, value);
|
|
@@ -9774,7 +10331,7 @@
|
|
|
9774
10331
|
// Children with data-bw_id or id attributes get local refs on the parent,
|
|
9775
10332
|
// so o.render functions can access them without any DOM lookup.
|
|
9776
10333
|
if (content != null) {
|
|
9777
|
-
if (
|
|
10334
|
+
if (_isA(content)) {
|
|
9778
10335
|
content.forEach(function (child) {
|
|
9779
10336
|
if (child != null) {
|
|
9780
10337
|
// Handle ComponentHandle in content arrays (Level 2 children)
|
|
@@ -9794,20 +10351,20 @@
|
|
|
9794
10351
|
if (childEl._bw_refs) {
|
|
9795
10352
|
if (!el._bw_refs) el._bw_refs = {};
|
|
9796
10353
|
for (var rk in childEl._bw_refs) {
|
|
9797
|
-
if (
|
|
10354
|
+
if (_hop.call(childEl._bw_refs, rk)) {
|
|
9798
10355
|
el._bw_refs[rk] = childEl._bw_refs[rk];
|
|
9799
10356
|
}
|
|
9800
10357
|
}
|
|
9801
10358
|
}
|
|
9802
10359
|
}
|
|
9803
10360
|
});
|
|
9804
|
-
} else if (
|
|
10361
|
+
} else if (_is(content, 'object') && content.__bw_raw) {
|
|
9805
10362
|
// Raw HTML content — inject via innerHTML
|
|
9806
10363
|
el.innerHTML = content.v;
|
|
9807
10364
|
} else if (content._bwComponent === true) {
|
|
9808
10365
|
// Single ComponentHandle as content
|
|
9809
10366
|
content.mount(el);
|
|
9810
|
-
} else if (
|
|
10367
|
+
} else if (_is(content, 'object') && content.t) {
|
|
9811
10368
|
var childEl = bw.createDOM(content, options);
|
|
9812
10369
|
el.appendChild(childEl);
|
|
9813
10370
|
var childBwId = content.a ? content.a['data-bw_id'] || content.a.id : null;
|
|
@@ -9818,7 +10375,7 @@
|
|
|
9818
10375
|
if (childEl._bw_refs) {
|
|
9819
10376
|
if (!el._bw_refs) el._bw_refs = {};
|
|
9820
10377
|
for (var rk in childEl._bw_refs) {
|
|
9821
|
-
if (
|
|
10378
|
+
if (_hop.call(childEl._bw_refs, rk)) {
|
|
9822
10379
|
el._bw_refs[rk] = childEl._bw_refs[rk];
|
|
9823
10380
|
}
|
|
9824
10381
|
}
|
|
@@ -9833,6 +10390,14 @@
|
|
|
9833
10390
|
bw._registerNode(el, null);
|
|
9834
10391
|
}
|
|
9835
10392
|
|
|
10393
|
+
// Register UUID class in node cache (bw_uuid_* tokens in class string)
|
|
10394
|
+
if (el.className) {
|
|
10395
|
+
var uuidMatch = el.className.match(_UUID_RE);
|
|
10396
|
+
if (uuidMatch) {
|
|
10397
|
+
bw._nodeMap[uuidMatch[0]] = el;
|
|
10398
|
+
}
|
|
10399
|
+
}
|
|
10400
|
+
|
|
9836
10401
|
// Handle lifecycle hooks and state
|
|
9837
10402
|
if (opts.mounted || opts.unmount || opts.render || opts.state) {
|
|
9838
10403
|
var id = attrs['data-bw_id'] || bw.uuid();
|
|
@@ -9850,7 +10415,7 @@
|
|
|
9850
10415
|
if (opts.render) {
|
|
9851
10416
|
el._bw_render = opts.render;
|
|
9852
10417
|
if (opts.mounted) {
|
|
9853
|
-
|
|
10418
|
+
_cw('bw.createDOM: o.render and o.mounted are mutually exclusive. o.render wins.');
|
|
9854
10419
|
}
|
|
9855
10420
|
|
|
9856
10421
|
// Queue initial render (same timing as mounted)
|
|
@@ -9922,7 +10487,7 @@
|
|
|
9922
10487
|
// Get target element (use cache-backed lookup)
|
|
9923
10488
|
var targetEl = bw._el(target);
|
|
9924
10489
|
if (!targetEl) {
|
|
9925
|
-
|
|
10490
|
+
_ce('bw.DOM: Target element not found:', target);
|
|
9926
10491
|
return null;
|
|
9927
10492
|
}
|
|
9928
10493
|
|
|
@@ -9960,7 +10525,7 @@
|
|
|
9960
10525
|
targetEl.appendChild(taco.element);
|
|
9961
10526
|
}
|
|
9962
10527
|
// Handle arrays
|
|
9963
|
-
else if (
|
|
10528
|
+
else if (_isA(taco)) {
|
|
9964
10529
|
taco.forEach(function (t) {
|
|
9965
10530
|
if (t != null) {
|
|
9966
10531
|
if (t._bwComponent === true) {
|
|
@@ -9995,7 +10560,7 @@
|
|
|
9995
10560
|
bw.compileProps = function (handle) {
|
|
9996
10561
|
var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
9997
10562
|
var compiledProps = {};
|
|
9998
|
-
|
|
10563
|
+
_keys(props).forEach(function (key) {
|
|
9999
10564
|
// Create getter/setter for each prop
|
|
10000
10565
|
Object.defineProperty(compiledProps, key, {
|
|
10001
10566
|
get: function get() {
|
|
@@ -10192,6 +10757,16 @@
|
|
|
10192
10757
|
bw.cleanup = function (element) {
|
|
10193
10758
|
if (!bw._isBrowser || !element) return;
|
|
10194
10759
|
|
|
10760
|
+
// Deregister UUID classes from node cache (element + descendants)
|
|
10761
|
+
// Covers elements that have UUID but no data-bw_id
|
|
10762
|
+
var selfUuidMatch = element.className && element.className.match(_UUID_RE);
|
|
10763
|
+
if (selfUuidMatch) delete bw._nodeMap[selfUuidMatch[0]];
|
|
10764
|
+
var uuidEls = element.querySelectorAll('[class*="bw_uuid_"]');
|
|
10765
|
+
uuidEls.forEach(function (uel) {
|
|
10766
|
+
var m = uel.className && uel.className.match(_UUID_RE);
|
|
10767
|
+
if (m) delete bw._nodeMap[m[0]];
|
|
10768
|
+
});
|
|
10769
|
+
|
|
10195
10770
|
// Find all elements with data-bw_id
|
|
10196
10771
|
var elements = element.querySelectorAll('[data-bw_id]');
|
|
10197
10772
|
elements.forEach(function (el) {
|
|
@@ -10205,6 +10780,10 @@
|
|
|
10205
10780
|
// Deregister from node cache
|
|
10206
10781
|
bw._deregisterNode(el, id);
|
|
10207
10782
|
|
|
10783
|
+
// Deregister UUID class from node cache
|
|
10784
|
+
var uuidMatch = el.className && el.className.match(_UUID_RE);
|
|
10785
|
+
if (uuidMatch) delete bw._nodeMap[uuidMatch[0]];
|
|
10786
|
+
|
|
10208
10787
|
// Clean up pub/sub subscriptions tied to this element
|
|
10209
10788
|
if (el._bw_subs) {
|
|
10210
10789
|
el._bw_subs.forEach(function (unsub) {
|
|
@@ -10231,6 +10810,10 @@
|
|
|
10231
10810
|
// Deregister from node cache
|
|
10232
10811
|
bw._deregisterNode(element, id);
|
|
10233
10812
|
|
|
10813
|
+
// Deregister UUID class from node cache
|
|
10814
|
+
var elemUuidMatch = element.className && element.className.match(_UUID_RE);
|
|
10815
|
+
if (elemUuidMatch) delete bw._nodeMap[elemUuidMatch[0]];
|
|
10816
|
+
|
|
10234
10817
|
// Clean up pub/sub subscriptions tied to element itself
|
|
10235
10818
|
if (element._bw_subs) {
|
|
10236
10819
|
element._bw_subs.forEach(function (unsub) {
|
|
@@ -10306,17 +10889,17 @@
|
|
|
10306
10889
|
if (attr) {
|
|
10307
10890
|
// Patch an attribute
|
|
10308
10891
|
el.setAttribute(attr, String(content));
|
|
10309
|
-
} else if (
|
|
10892
|
+
} else if (_isA(content)) {
|
|
10310
10893
|
// Patch with array of children (strings and/or TACOs)
|
|
10311
10894
|
el.innerHTML = '';
|
|
10312
10895
|
content.forEach(function (item) {
|
|
10313
|
-
if (
|
|
10896
|
+
if (_is(item, 'string') || _is(item, 'number')) {
|
|
10314
10897
|
el.appendChild(document.createTextNode(String(item)));
|
|
10315
10898
|
} else if (item && item.t) {
|
|
10316
10899
|
el.appendChild(bw.createDOM(item));
|
|
10317
10900
|
}
|
|
10318
10901
|
});
|
|
10319
|
-
} else if (
|
|
10902
|
+
} else if (_is(content, 'object') && content.t) {
|
|
10320
10903
|
// Patch with a TACO — replace children
|
|
10321
10904
|
el.innerHTML = '';
|
|
10322
10905
|
el.appendChild(bw.createDOM(content));
|
|
@@ -10347,7 +10930,7 @@
|
|
|
10347
10930
|
bw.patchAll = function (patches) {
|
|
10348
10931
|
var results = {};
|
|
10349
10932
|
for (var id in patches) {
|
|
10350
|
-
if (
|
|
10933
|
+
if (_hop.call(patches, id)) {
|
|
10351
10934
|
results[id] = bw.patch(id, patches[id]);
|
|
10352
10935
|
}
|
|
10353
10936
|
}
|
|
@@ -10444,7 +11027,7 @@
|
|
|
10444
11027
|
snapshot[i].handler(detail);
|
|
10445
11028
|
called++;
|
|
10446
11029
|
} catch (err) {
|
|
10447
|
-
|
|
11030
|
+
_cw('bw.pub: subscriber error on topic "' + topic + '":', err);
|
|
10448
11031
|
}
|
|
10449
11032
|
}
|
|
10450
11033
|
return called;
|
|
@@ -10545,8 +11128,8 @@
|
|
|
10545
11128
|
* @see bw.funcGetDispatchStr
|
|
10546
11129
|
*/
|
|
10547
11130
|
bw.funcRegister = function (fn, name) {
|
|
10548
|
-
if (
|
|
10549
|
-
var fnID =
|
|
11131
|
+
if (!_is(fn, 'function')) return '';
|
|
11132
|
+
var fnID = _is(name, 'string') && name.length > 0 ? name : 'bw_fn_' + bw._fnIDCounter++;
|
|
10550
11133
|
bw._fnRegistry[fnID] = fn;
|
|
10551
11134
|
return fnID;
|
|
10552
11135
|
};
|
|
@@ -10565,8 +11148,8 @@
|
|
|
10565
11148
|
bw.funcGetById = function (name, errFn) {
|
|
10566
11149
|
name = String(name);
|
|
10567
11150
|
if (name in bw._fnRegistry) return bw._fnRegistry[name];
|
|
10568
|
-
return
|
|
10569
|
-
|
|
11151
|
+
return _is(errFn, 'function') ? errFn : function () {
|
|
11152
|
+
_cw('bw.funcGetById: unregistered fn "' + name + '"');
|
|
10570
11153
|
};
|
|
10571
11154
|
};
|
|
10572
11155
|
|
|
@@ -10608,13 +11191,23 @@
|
|
|
10608
11191
|
bw.funcGetRegistry = function () {
|
|
10609
11192
|
var copy = {};
|
|
10610
11193
|
for (var k in bw._fnRegistry) {
|
|
10611
|
-
if (
|
|
11194
|
+
if (_hop.call(bw._fnRegistry, k)) {
|
|
10612
11195
|
copy[k] = bw._fnRegistry[k];
|
|
10613
11196
|
}
|
|
10614
11197
|
}
|
|
10615
11198
|
return copy;
|
|
10616
11199
|
};
|
|
10617
11200
|
|
|
11201
|
+
/**
|
|
11202
|
+
* Minimal runtime shim for funcRegister dispatch in static HTML.
|
|
11203
|
+
* When embedded in a `<script>` tag, provides just enough infrastructure
|
|
11204
|
+
* for `bw.funcGetById()` calls to resolve. The actual function bodies
|
|
11205
|
+
* are emitted separately as `bw._fnRegistry['bw_fn_X'] = ...;` assignments.
|
|
11206
|
+
* @type {string}
|
|
11207
|
+
* @category Function Registry
|
|
11208
|
+
*/
|
|
11209
|
+
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;})();';
|
|
11210
|
+
|
|
10618
11211
|
// ===================================================================================
|
|
10619
11212
|
// Template Binding Utilities
|
|
10620
11213
|
// ===================================================================================
|
|
@@ -10646,7 +11239,10 @@
|
|
|
10646
11239
|
var parts = path.split('.');
|
|
10647
11240
|
var val = state;
|
|
10648
11241
|
for (var i = 0; i < parts.length; i++) {
|
|
10649
|
-
if (val == null)
|
|
11242
|
+
if (val == null) {
|
|
11243
|
+
if (bw.debug) _cw('bw.debug: _evaluatePath — null at key "' + parts[i] + '" in path "' + path + '"');
|
|
11244
|
+
return '';
|
|
11245
|
+
}
|
|
10650
11246
|
val = val[parts[i]];
|
|
10651
11247
|
}
|
|
10652
11248
|
return val == null ? '' : val;
|
|
@@ -10666,7 +11262,7 @@
|
|
|
10666
11262
|
*/
|
|
10667
11263
|
bw._compiledExprs = {};
|
|
10668
11264
|
bw._resolveTemplate = function (str, state, compile) {
|
|
10669
|
-
if (
|
|
11265
|
+
if (!_is(str, 'string') || str.indexOf('${') < 0) return str;
|
|
10670
11266
|
var bindings = bw._parseBindings(str);
|
|
10671
11267
|
if (bindings.length === 0) return str;
|
|
10672
11268
|
var result = '';
|
|
@@ -10689,6 +11285,7 @@
|
|
|
10689
11285
|
try {
|
|
10690
11286
|
val = bw._compiledExprs[b.expr](state);
|
|
10691
11287
|
} catch (e) {
|
|
11288
|
+
if (bw.debug) _cw('bw.debug: _resolveTemplate — Tier 2 eval failed for "${' + b.expr + '}":', e.message);
|
|
10692
11289
|
val = '';
|
|
10693
11290
|
}
|
|
10694
11291
|
} else {
|
|
@@ -10796,7 +11393,7 @@
|
|
|
10796
11393
|
this._state = {};
|
|
10797
11394
|
if (o.state) {
|
|
10798
11395
|
for (var k in o.state) {
|
|
10799
|
-
if (
|
|
11396
|
+
if (_hop.call(o.state, k)) {
|
|
10800
11397
|
this._state[k] = o.state[k];
|
|
10801
11398
|
}
|
|
10802
11399
|
}
|
|
@@ -10805,7 +11402,7 @@
|
|
|
10805
11402
|
this._actions = {};
|
|
10806
11403
|
if (o.actions) {
|
|
10807
11404
|
for (var k2 in o.actions) {
|
|
10808
|
-
if (
|
|
11405
|
+
if (_hop.call(o.actions, k2)) {
|
|
10809
11406
|
this._actions[k2] = o.actions[k2];
|
|
10810
11407
|
}
|
|
10811
11408
|
}
|
|
@@ -10815,7 +11412,7 @@
|
|
|
10815
11412
|
if (o.methods) {
|
|
10816
11413
|
var self = this;
|
|
10817
11414
|
for (var k3 in o.methods) {
|
|
10818
|
-
if (
|
|
11415
|
+
if (_hop.call(o.methods, k3)) {
|
|
10819
11416
|
this._methods[k3] = o.methods[k3];
|
|
10820
11417
|
(function (methodName, methodFn) {
|
|
10821
11418
|
self[methodName] = function () {
|
|
@@ -10833,7 +11430,7 @@
|
|
|
10833
11430
|
willMount: o.willMount || null,
|
|
10834
11431
|
mounted: o.mounted || null,
|
|
10835
11432
|
willUpdate: o.willUpdate || null,
|
|
10836
|
-
onUpdate: o.onUpdate || null,
|
|
11433
|
+
onUpdate: o.onUpdate || o.updated || null,
|
|
10837
11434
|
unmount: o.unmount || null,
|
|
10838
11435
|
willDestroy: o.willDestroy || null
|
|
10839
11436
|
};
|
|
@@ -10848,14 +11445,23 @@
|
|
|
10848
11445
|
this._compile = !!o.compile;
|
|
10849
11446
|
this._bw_refs = {};
|
|
10850
11447
|
this._refCounter = 0;
|
|
11448
|
+
// Child component ownership (Bug #5)
|
|
11449
|
+
this._children = [];
|
|
11450
|
+
this._parent = null;
|
|
11451
|
+
// Factory metadata for BCCL rebuild (Bug #6)
|
|
11452
|
+
this._factory = taco._bwFactory || null;
|
|
10851
11453
|
}
|
|
10852
11454
|
|
|
11455
|
+
// Short alias for ComponentHandle.prototype (see alias block at top of file).
|
|
11456
|
+
// 28 method definitions × 25 chars = ~700B raw savings in minified output.
|
|
11457
|
+
var _chp = ComponentHandle.prototype;
|
|
11458
|
+
|
|
10853
11459
|
// ── State Methods ──
|
|
10854
11460
|
|
|
10855
11461
|
/**
|
|
10856
11462
|
* Get a state value. Dot-path supported: `get('user.name')`
|
|
10857
11463
|
*/
|
|
10858
|
-
|
|
11464
|
+
_chp.get = function (key) {
|
|
10859
11465
|
return bw._evaluatePath(this._state, key);
|
|
10860
11466
|
};
|
|
10861
11467
|
|
|
@@ -10865,12 +11471,13 @@
|
|
|
10865
11471
|
* @param {*} value - New value
|
|
10866
11472
|
* @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
|
|
10867
11473
|
*/
|
|
10868
|
-
|
|
11474
|
+
_chp.set = function (key, value, opts) {
|
|
10869
11475
|
// Dot-path set
|
|
10870
11476
|
var parts = key.split('.');
|
|
10871
11477
|
var obj = this._state;
|
|
10872
11478
|
for (var i = 0; i < parts.length - 1; i++) {
|
|
10873
|
-
if (
|
|
11479
|
+
if (!_is(obj[parts[i]], 'object')) {
|
|
11480
|
+
if (bw.debug) _cw('bw.debug: set() — auto-creating intermediate "' + parts[i] + '" in path "' + key + '"');
|
|
10874
11481
|
obj[parts[i]] = {};
|
|
10875
11482
|
}
|
|
10876
11483
|
obj = obj[parts[i]];
|
|
@@ -10890,10 +11497,10 @@
|
|
|
10890
11497
|
/**
|
|
10891
11498
|
* Get a shallow clone of the full state.
|
|
10892
11499
|
*/
|
|
10893
|
-
|
|
11500
|
+
_chp.getState = function () {
|
|
10894
11501
|
var clone = {};
|
|
10895
11502
|
for (var k in this._state) {
|
|
10896
|
-
if (
|
|
11503
|
+
if (_hop.call(this._state, k)) {
|
|
10897
11504
|
clone[k] = this._state[k];
|
|
10898
11505
|
}
|
|
10899
11506
|
}
|
|
@@ -10905,9 +11512,9 @@
|
|
|
10905
11512
|
* @param {Object} updates - Key-value pairs to merge
|
|
10906
11513
|
* @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
|
|
10907
11514
|
*/
|
|
10908
|
-
|
|
11515
|
+
_chp.setState = function (updates, opts) {
|
|
10909
11516
|
for (var k in updates) {
|
|
10910
|
-
if (
|
|
11517
|
+
if (_hop.call(updates, k)) {
|
|
10911
11518
|
this._state[k] = updates[k];
|
|
10912
11519
|
this._dirtyKeys[k] = true;
|
|
10913
11520
|
}
|
|
@@ -10924,9 +11531,9 @@
|
|
|
10924
11531
|
/**
|
|
10925
11532
|
* Push a value onto an array in state. Clones the array.
|
|
10926
11533
|
*/
|
|
10927
|
-
|
|
11534
|
+
_chp.push = function (key, val) {
|
|
10928
11535
|
var arr = this.get(key);
|
|
10929
|
-
var newArr =
|
|
11536
|
+
var newArr = _isA(arr) ? arr.slice() : [];
|
|
10930
11537
|
newArr.push(val);
|
|
10931
11538
|
this.set(key, newArr);
|
|
10932
11539
|
};
|
|
@@ -10934,9 +11541,9 @@
|
|
|
10934
11541
|
/**
|
|
10935
11542
|
* Splice an array in state. Clones the array.
|
|
10936
11543
|
*/
|
|
10937
|
-
|
|
11544
|
+
_chp.splice = function (key, start, deleteCount) {
|
|
10938
11545
|
var arr = this.get(key);
|
|
10939
|
-
var newArr =
|
|
11546
|
+
var newArr = _isA(arr) ? arr.slice() : [];
|
|
10940
11547
|
var args = [start, deleteCount].concat(Array.prototype.slice.call(arguments, 3));
|
|
10941
11548
|
Array.prototype.splice.apply(newArr, args);
|
|
10942
11549
|
this.set(key, newArr);
|
|
@@ -10944,7 +11551,7 @@
|
|
|
10944
11551
|
|
|
10945
11552
|
// ── Scheduling ──
|
|
10946
11553
|
|
|
10947
|
-
|
|
11554
|
+
_chp._scheduleDirty = function () {
|
|
10948
11555
|
if (!this._scheduled) {
|
|
10949
11556
|
this._scheduled = true;
|
|
10950
11557
|
bw._dirtyComponents.push(this);
|
|
@@ -10959,16 +11566,16 @@
|
|
|
10959
11566
|
* Creates binding descriptors with refIds for targeted DOM updates.
|
|
10960
11567
|
* @private
|
|
10961
11568
|
*/
|
|
10962
|
-
|
|
11569
|
+
_chp._compileBindings = function () {
|
|
10963
11570
|
this._bindings = [];
|
|
10964
11571
|
this._refCounter = 0;
|
|
10965
|
-
var stateKeys =
|
|
11572
|
+
var stateKeys = _keys(this._state);
|
|
10966
11573
|
var self = this;
|
|
10967
11574
|
function walkTaco(taco, path) {
|
|
10968
|
-
if (
|
|
11575
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
10969
11576
|
|
|
10970
11577
|
// Check content for bindings
|
|
10971
|
-
if (
|
|
11578
|
+
if (_is(taco.c, 'string') && taco.c.indexOf('${') >= 0) {
|
|
10972
11579
|
var refId = 'bw_ref_' + self._refCounter++;
|
|
10973
11580
|
var parsed = bw._parseBindings(taco.c);
|
|
10974
11581
|
var deps = [];
|
|
@@ -10990,10 +11597,10 @@
|
|
|
10990
11597
|
// Check attributes for bindings
|
|
10991
11598
|
if (taco.a) {
|
|
10992
11599
|
for (var attrName in taco.a) {
|
|
10993
|
-
if (!
|
|
11600
|
+
if (!_hop.call(taco.a, attrName)) continue;
|
|
10994
11601
|
if (attrName === 'data-bw_ref') continue;
|
|
10995
11602
|
var attrVal = taco.a[attrName];
|
|
10996
|
-
if (
|
|
11603
|
+
if (_is(attrVal, 'string') && attrVal.indexOf('${') >= 0) {
|
|
10997
11604
|
var refId2 = 'bw_ref_' + self._refCounter++;
|
|
10998
11605
|
var parsed2 = bw._parseBindings(attrVal);
|
|
10999
11606
|
var deps2 = [];
|
|
@@ -11019,9 +11626,34 @@
|
|
|
11019
11626
|
}
|
|
11020
11627
|
|
|
11021
11628
|
// Recurse into children
|
|
11022
|
-
if (
|
|
11629
|
+
if (_isA(taco.c)) {
|
|
11023
11630
|
for (var i = 0; i < taco.c.length; i++) {
|
|
11024
|
-
|
|
11631
|
+
// Wrap string children with ${expr} in a span so patches target the span, not the parent
|
|
11632
|
+
if (_is(taco.c[i], 'string') && taco.c[i].indexOf('${') >= 0) {
|
|
11633
|
+
var mixedRefId = 'bw_ref_' + self._refCounter++;
|
|
11634
|
+
var mixedParsed = bw._parseBindings(taco.c[i]);
|
|
11635
|
+
var mixedDeps = [];
|
|
11636
|
+
for (var mi = 0; mi < mixedParsed.length; mi++) {
|
|
11637
|
+
mixedDeps = mixedDeps.concat(bw._extractDeps(mixedParsed[mi].expr, stateKeys));
|
|
11638
|
+
}
|
|
11639
|
+
self._bindings.push({
|
|
11640
|
+
expr: taco.c[i],
|
|
11641
|
+
type: 'content',
|
|
11642
|
+
refId: mixedRefId,
|
|
11643
|
+
deps: mixedDeps,
|
|
11644
|
+
template: taco.c[i]
|
|
11645
|
+
});
|
|
11646
|
+
// Replace string with a span wrapper so textContent targets the span only
|
|
11647
|
+
taco.c[i] = {
|
|
11648
|
+
t: 'span',
|
|
11649
|
+
a: {
|
|
11650
|
+
'data-bw_ref': mixedRefId,
|
|
11651
|
+
style: 'display:contents'
|
|
11652
|
+
},
|
|
11653
|
+
c: taco.c[i]
|
|
11654
|
+
};
|
|
11655
|
+
}
|
|
11656
|
+
if (_is(taco.c[i], 'object') && taco.c[i].t) {
|
|
11025
11657
|
walkTaco(taco.c[i], path.concat(i));
|
|
11026
11658
|
}
|
|
11027
11659
|
// Handle bw.when/bw.each markers
|
|
@@ -11056,7 +11688,7 @@
|
|
|
11056
11688
|
taco.c[i]._refId = eachRefId;
|
|
11057
11689
|
}
|
|
11058
11690
|
}
|
|
11059
|
-
} else if (
|
|
11691
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
11060
11692
|
walkTaco(taco.c, path.concat(0));
|
|
11061
11693
|
}
|
|
11062
11694
|
return taco;
|
|
@@ -11070,7 +11702,7 @@
|
|
|
11070
11702
|
* Build ref map from the live DOM after createDOM.
|
|
11071
11703
|
* @private
|
|
11072
11704
|
*/
|
|
11073
|
-
|
|
11705
|
+
_chp._collectRefs = function () {
|
|
11074
11706
|
this._bw_refs = {};
|
|
11075
11707
|
if (!this.element) return;
|
|
11076
11708
|
var els = this.element.querySelectorAll('[data-bw_ref]');
|
|
@@ -11091,7 +11723,7 @@
|
|
|
11091
11723
|
* Creates DOM, compiles bindings, registers actions, and calls lifecycle hooks.
|
|
11092
11724
|
* @param {Element} parentEl - DOM element to mount into
|
|
11093
11725
|
*/
|
|
11094
|
-
|
|
11726
|
+
_chp.mount = function (parentEl) {
|
|
11095
11727
|
// willMount hook
|
|
11096
11728
|
if (this._hooks.willMount) this._hooks.willMount(this);
|
|
11097
11729
|
|
|
@@ -11113,7 +11745,7 @@
|
|
|
11113
11745
|
// Register named actions in function registry
|
|
11114
11746
|
var self = this;
|
|
11115
11747
|
for (var actionName in this._actions) {
|
|
11116
|
-
if (
|
|
11748
|
+
if (_hop.call(this._actions, actionName)) {
|
|
11117
11749
|
var registeredName = this._bwId + '_' + actionName;
|
|
11118
11750
|
(function (aName) {
|
|
11119
11751
|
bw.funcRegister(function (evt) {
|
|
@@ -11132,6 +11764,11 @@
|
|
|
11132
11764
|
this.element = bw.createDOM(tacoForDOM);
|
|
11133
11765
|
this.element._bwComponentHandle = this;
|
|
11134
11766
|
this.element.setAttribute('data-bw_comp_id', this._bwId);
|
|
11767
|
+
|
|
11768
|
+
// Restore o.render from original TACO (stripped by _tacoForDOM)
|
|
11769
|
+
if (this.taco.o && this.taco.o.render) {
|
|
11770
|
+
this.element._bw_render = this.taco.o.render;
|
|
11771
|
+
}
|
|
11135
11772
|
if (this._userTag) {
|
|
11136
11773
|
this.element.classList.add(this._userTag);
|
|
11137
11774
|
}
|
|
@@ -11146,6 +11783,16 @@
|
|
|
11146
11783
|
this._resolveAndApplyAll();
|
|
11147
11784
|
this.mounted = true;
|
|
11148
11785
|
|
|
11786
|
+
// Scan for child ComponentHandles and link parent/child (Bug #5)
|
|
11787
|
+
var childEls = this.element.querySelectorAll('[data-bw_comp_id]');
|
|
11788
|
+
for (var ci = 0; ci < childEls.length; ci++) {
|
|
11789
|
+
var ch = childEls[ci]._bwComponentHandle;
|
|
11790
|
+
if (ch && ch !== this && !ch._parent) {
|
|
11791
|
+
ch._parent = this;
|
|
11792
|
+
this._children.push(ch);
|
|
11793
|
+
}
|
|
11794
|
+
}
|
|
11795
|
+
|
|
11149
11796
|
// mounted hook (backward compat: fn.length === 2 wraps (el, state))
|
|
11150
11797
|
if (this._hooks.mounted) {
|
|
11151
11798
|
if (this._hooks.mounted.length === 2) {
|
|
@@ -11154,15 +11801,20 @@
|
|
|
11154
11801
|
this._hooks.mounted(this);
|
|
11155
11802
|
}
|
|
11156
11803
|
}
|
|
11804
|
+
|
|
11805
|
+
// Invoke o.render on initial mount (if present)
|
|
11806
|
+
if (this.element._bw_render) {
|
|
11807
|
+
this.element._bw_render(this.element, this._state);
|
|
11808
|
+
}
|
|
11157
11809
|
};
|
|
11158
11810
|
|
|
11159
11811
|
/**
|
|
11160
11812
|
* Prepare TACO for initial render: resolve when/each markers.
|
|
11161
11813
|
* @private
|
|
11162
11814
|
*/
|
|
11163
|
-
|
|
11164
|
-
if (!
|
|
11165
|
-
if (
|
|
11815
|
+
_chp._prepareTaco = function (taco) {
|
|
11816
|
+
if (!_is(taco, 'object')) return;
|
|
11817
|
+
if (_isA(taco.c)) {
|
|
11166
11818
|
for (var i = taco.c.length - 1; i >= 0; i--) {
|
|
11167
11819
|
var child = taco.c[i];
|
|
11168
11820
|
if (child && child._bwWhen) {
|
|
@@ -11203,7 +11855,7 @@
|
|
|
11203
11855
|
var eachExprStr = child.expr.replace(/^\$\{|\}$/g, '');
|
|
11204
11856
|
var arr = bw._evaluatePath(this._state, eachExprStr);
|
|
11205
11857
|
var items = [];
|
|
11206
|
-
if (
|
|
11858
|
+
if (_isA(arr)) {
|
|
11207
11859
|
for (var j = 0; j < arr.length; j++) {
|
|
11208
11860
|
items.push(child.factory(arr[j], j));
|
|
11209
11861
|
}
|
|
@@ -11217,11 +11869,11 @@
|
|
|
11217
11869
|
c: items
|
|
11218
11870
|
};
|
|
11219
11871
|
}
|
|
11220
|
-
if (
|
|
11872
|
+
if (_is(taco.c[i], 'object') && taco.c[i].t) {
|
|
11221
11873
|
this._prepareTaco(taco.c[i]);
|
|
11222
11874
|
}
|
|
11223
11875
|
}
|
|
11224
|
-
} else if (
|
|
11876
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
11225
11877
|
this._prepareTaco(taco.c);
|
|
11226
11878
|
}
|
|
11227
11879
|
};
|
|
@@ -11230,12 +11882,12 @@
|
|
|
11230
11882
|
* Wire action name strings (in onclick etc.) to dispatch function calls.
|
|
11231
11883
|
* @private
|
|
11232
11884
|
*/
|
|
11233
|
-
|
|
11234
|
-
if (!
|
|
11885
|
+
_chp._wireActions = function (taco) {
|
|
11886
|
+
if (!_is(taco, 'object') || !taco.t) return;
|
|
11235
11887
|
if (taco.a) {
|
|
11236
11888
|
for (var key in taco.a) {
|
|
11237
|
-
if (!
|
|
11238
|
-
if (key.startsWith('on') &&
|
|
11889
|
+
if (!_hop.call(taco.a, key)) continue;
|
|
11890
|
+
if (key.startsWith('on') && _is(taco.a[key], 'string')) {
|
|
11239
11891
|
var actionName = taco.a[key];
|
|
11240
11892
|
if (actionName in this._actions) {
|
|
11241
11893
|
var registeredName = this._bwId + '_' + actionName;
|
|
@@ -11249,11 +11901,11 @@
|
|
|
11249
11901
|
}
|
|
11250
11902
|
}
|
|
11251
11903
|
}
|
|
11252
|
-
if (
|
|
11904
|
+
if (_isA(taco.c)) {
|
|
11253
11905
|
for (var i = 0; i < taco.c.length; i++) {
|
|
11254
11906
|
this._wireActions(taco.c[i]);
|
|
11255
11907
|
}
|
|
11256
|
-
} else if (
|
|
11908
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
11257
11909
|
this._wireActions(taco.c);
|
|
11258
11910
|
}
|
|
11259
11911
|
};
|
|
@@ -11262,7 +11914,7 @@
|
|
|
11262
11914
|
* Deep-clone a TACO tree, preserving _bwWhen/_bwEach markers and their factories.
|
|
11263
11915
|
* @private
|
|
11264
11916
|
*/
|
|
11265
|
-
|
|
11917
|
+
_chp._deepCloneTaco = function (taco) {
|
|
11266
11918
|
if (taco == null) return taco;
|
|
11267
11919
|
// Preserve _bwWhen / _bwEach markers (contain functions)
|
|
11268
11920
|
if (taco._bwWhen) {
|
|
@@ -11281,22 +11933,22 @@
|
|
|
11281
11933
|
_refId: taco._refId
|
|
11282
11934
|
};
|
|
11283
11935
|
}
|
|
11284
|
-
if (
|
|
11936
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
11285
11937
|
var result = {
|
|
11286
11938
|
t: taco.t
|
|
11287
11939
|
};
|
|
11288
11940
|
if (taco.a) {
|
|
11289
11941
|
result.a = {};
|
|
11290
11942
|
for (var k in taco.a) {
|
|
11291
|
-
if (
|
|
11943
|
+
if (_hop.call(taco.a, k)) result.a[k] = taco.a[k];
|
|
11292
11944
|
}
|
|
11293
11945
|
}
|
|
11294
11946
|
if (taco.c != null) {
|
|
11295
|
-
if (
|
|
11947
|
+
if (_isA(taco.c)) {
|
|
11296
11948
|
result.c = taco.c.map(function (child) {
|
|
11297
11949
|
return this._deepCloneTaco(child);
|
|
11298
11950
|
}.bind(this));
|
|
11299
|
-
} else if (
|
|
11951
|
+
} else if (_is(taco.c, 'object')) {
|
|
11300
11952
|
result.c = this._deepCloneTaco(taco.c);
|
|
11301
11953
|
} else {
|
|
11302
11954
|
result.c = taco.c;
|
|
@@ -11310,31 +11962,34 @@
|
|
|
11310
11962
|
* Create a copy of TACO suitable for createDOM (strips o to prevent double lifecycle).
|
|
11311
11963
|
* @private
|
|
11312
11964
|
*/
|
|
11313
|
-
|
|
11314
|
-
if (!
|
|
11965
|
+
_chp._tacoForDOM = function (taco) {
|
|
11966
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
11315
11967
|
var result = {
|
|
11316
11968
|
t: taco.t
|
|
11317
11969
|
};
|
|
11318
11970
|
if (taco.a) result.a = taco.a;
|
|
11319
11971
|
if (taco.c != null) {
|
|
11320
|
-
if (
|
|
11972
|
+
if (_isA(taco.c)) {
|
|
11321
11973
|
result.c = taco.c.map(function (child) {
|
|
11322
11974
|
return this._tacoForDOM(child);
|
|
11323
11975
|
}.bind(this));
|
|
11324
|
-
} else if (
|
|
11976
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
11325
11977
|
result.c = this._tacoForDOM(taco.c);
|
|
11326
11978
|
} else {
|
|
11327
11979
|
result.c = taco.c;
|
|
11328
11980
|
}
|
|
11329
11981
|
}
|
|
11330
11982
|
// Intentionally strip o (no mounted/unmount/state/render on sub-elements)
|
|
11983
|
+
if (taco.o && (taco.o.mounted || taco.o.render || taco.o.unmount)) {
|
|
11984
|
+
_cw('bw: _tacoForDOM stripped o.mounted/render/unmount from child <' + taco.t + '>. Use onclick attribute or bw.component() for child interactivity.');
|
|
11985
|
+
}
|
|
11331
11986
|
return result;
|
|
11332
11987
|
};
|
|
11333
11988
|
|
|
11334
11989
|
/**
|
|
11335
11990
|
* Unmount: remove from DOM, deactivate, preserve state for re-mount.
|
|
11336
11991
|
*/
|
|
11337
|
-
|
|
11992
|
+
_chp.unmount = function () {
|
|
11338
11993
|
if (!this.mounted) return;
|
|
11339
11994
|
|
|
11340
11995
|
// unmount hook
|
|
@@ -11368,11 +12023,22 @@
|
|
|
11368
12023
|
/**
|
|
11369
12024
|
* Destroy: unmount + clear state + unregister actions.
|
|
11370
12025
|
*/
|
|
11371
|
-
|
|
12026
|
+
_chp.destroy = function () {
|
|
11372
12027
|
// willDestroy hook
|
|
11373
12028
|
if (this._hooks.willDestroy) {
|
|
11374
12029
|
this._hooks.willDestroy(this);
|
|
11375
12030
|
}
|
|
12031
|
+
|
|
12032
|
+
// Cascade destroy to children depth-first (Bug #5)
|
|
12033
|
+
for (var ci = this._children.length - 1; ci >= 0; ci--) {
|
|
12034
|
+
this._children[ci].destroy();
|
|
12035
|
+
}
|
|
12036
|
+
this._children = [];
|
|
12037
|
+
if (this._parent) {
|
|
12038
|
+
var idx = this._parent._children.indexOf(this);
|
|
12039
|
+
if (idx >= 0) this._parent._children.splice(idx, 1);
|
|
12040
|
+
this._parent = null;
|
|
12041
|
+
}
|
|
11376
12042
|
this.unmount();
|
|
11377
12043
|
|
|
11378
12044
|
// Unregister actions from function registry
|
|
@@ -11399,12 +12065,37 @@
|
|
|
11399
12065
|
* Flush dirty state: resolve changed bindings and apply to DOM.
|
|
11400
12066
|
* @private
|
|
11401
12067
|
*/
|
|
11402
|
-
|
|
12068
|
+
_chp._flush = function () {
|
|
11403
12069
|
this._scheduled = false;
|
|
11404
|
-
var changedKeys =
|
|
12070
|
+
var changedKeys = _keys(this._dirtyKeys);
|
|
11405
12071
|
this._dirtyKeys = {};
|
|
11406
12072
|
if (changedKeys.length === 0 || !this.mounted) return;
|
|
11407
12073
|
|
|
12074
|
+
// Factory rebuild: if a BCCL factory exists and changed keys overlap factory props,
|
|
12075
|
+
// rebuild the TACO from the factory with merged state (Bug #6)
|
|
12076
|
+
if (this._factory) {
|
|
12077
|
+
var rebuildNeeded = false;
|
|
12078
|
+
for (var fi = 0; fi < changedKeys.length; fi++) {
|
|
12079
|
+
if (_hop.call(this._factory.props, changedKeys[fi])) {
|
|
12080
|
+
rebuildNeeded = true;
|
|
12081
|
+
break;
|
|
12082
|
+
}
|
|
12083
|
+
}
|
|
12084
|
+
if (rebuildNeeded) {
|
|
12085
|
+
var merged = {};
|
|
12086
|
+
for (var mk in this._factory.props) if (_hop.call(this._factory.props, mk)) merged[mk] = this._factory.props[mk];
|
|
12087
|
+
for (var sk in this._state) if (_hop.call(this._state, sk)) merged[sk] = this._state[sk];
|
|
12088
|
+
this._factory.props = merged;
|
|
12089
|
+
var newTaco = bw.make(this._factory.type, merged);
|
|
12090
|
+
newTaco._bwFactory = this._factory;
|
|
12091
|
+
this.taco = newTaco;
|
|
12092
|
+
this._originalTaco = this._deepCloneTaco(newTaco);
|
|
12093
|
+
this._render();
|
|
12094
|
+
if (this._hooks.onUpdate) this._hooks.onUpdate(this, changedKeys);
|
|
12095
|
+
return;
|
|
12096
|
+
}
|
|
12097
|
+
}
|
|
12098
|
+
|
|
11408
12099
|
// willUpdate hook
|
|
11409
12100
|
if (this._hooks.willUpdate) {
|
|
11410
12101
|
this._hooks.willUpdate(this, changedKeys);
|
|
@@ -11442,7 +12133,7 @@
|
|
|
11442
12133
|
* Returns list of patches to apply.
|
|
11443
12134
|
* @private
|
|
11444
12135
|
*/
|
|
11445
|
-
|
|
12136
|
+
_chp._resolveBindings = function (changedKeys) {
|
|
11446
12137
|
var patches = [];
|
|
11447
12138
|
for (var i = 0; i < this._bindings.length; i++) {
|
|
11448
12139
|
var b = this._bindings[i];
|
|
@@ -11478,11 +12169,14 @@
|
|
|
11478
12169
|
* Apply patches to DOM.
|
|
11479
12170
|
* @private
|
|
11480
12171
|
*/
|
|
11481
|
-
|
|
12172
|
+
_chp._applyPatches = function (patches) {
|
|
11482
12173
|
for (var i = 0; i < patches.length; i++) {
|
|
11483
12174
|
var p = patches[i];
|
|
11484
12175
|
var el = this._bw_refs[p.refId];
|
|
11485
|
-
if (!el)
|
|
12176
|
+
if (!el) {
|
|
12177
|
+
if (bw.debug) _cw('bw.debug: _applyPatches — ref "' + p.refId + '" not found in DOM');
|
|
12178
|
+
continue;
|
|
12179
|
+
}
|
|
11486
12180
|
if (p.type === 'content') {
|
|
11487
12181
|
el.textContent = p.value;
|
|
11488
12182
|
} else if (p.type === 'attribute') {
|
|
@@ -11499,7 +12193,7 @@
|
|
|
11499
12193
|
* Resolve all bindings and apply (used for initial render).
|
|
11500
12194
|
* @private
|
|
11501
12195
|
*/
|
|
11502
|
-
|
|
12196
|
+
_chp._resolveAndApplyAll = function () {
|
|
11503
12197
|
var patches = [];
|
|
11504
12198
|
for (var i = 0; i < this._bindings.length; i++) {
|
|
11505
12199
|
var b = this._bindings[i];
|
|
@@ -11521,7 +12215,7 @@
|
|
|
11521
12215
|
* Full re-render for structural changes (when/each branch switches).
|
|
11522
12216
|
* @private
|
|
11523
12217
|
*/
|
|
11524
|
-
|
|
12218
|
+
_chp._render = function () {
|
|
11525
12219
|
if (!this.element || !this.element.parentNode) return;
|
|
11526
12220
|
var parent = this.element.parentNode;
|
|
11527
12221
|
var nextSibling = this.element.nextSibling;
|
|
@@ -11560,7 +12254,7 @@
|
|
|
11560
12254
|
* @param {string} event - Event name (e.g., 'click')
|
|
11561
12255
|
* @param {Function} handler - Event handler
|
|
11562
12256
|
*/
|
|
11563
|
-
|
|
12257
|
+
_chp.on = function (event, handler) {
|
|
11564
12258
|
if (this.element) {
|
|
11565
12259
|
this.element.addEventListener(event, handler);
|
|
11566
12260
|
}
|
|
@@ -11575,7 +12269,7 @@
|
|
|
11575
12269
|
* @param {string} event - Event name
|
|
11576
12270
|
* @param {Function} handler - Handler to remove
|
|
11577
12271
|
*/
|
|
11578
|
-
|
|
12272
|
+
_chp.off = function (event, handler) {
|
|
11579
12273
|
if (this.element) {
|
|
11580
12274
|
this.element.removeEventListener(event, handler);
|
|
11581
12275
|
}
|
|
@@ -11590,7 +12284,7 @@
|
|
|
11590
12284
|
* @param {Function} handler - Handler function
|
|
11591
12285
|
* @returns {Function} Unsubscribe function
|
|
11592
12286
|
*/
|
|
11593
|
-
|
|
12287
|
+
_chp.sub = function (topic, handler) {
|
|
11594
12288
|
var unsub = bw.sub(topic, handler);
|
|
11595
12289
|
this._subs.push(unsub);
|
|
11596
12290
|
return unsub;
|
|
@@ -11601,10 +12295,10 @@
|
|
|
11601
12295
|
* @param {string} name - Action name
|
|
11602
12296
|
* @param {...*} args - Arguments passed after comp
|
|
11603
12297
|
*/
|
|
11604
|
-
|
|
12298
|
+
_chp.action = function (name) {
|
|
11605
12299
|
var fn = this._actions[name];
|
|
11606
12300
|
if (!fn) {
|
|
11607
|
-
|
|
12301
|
+
_cw('ComponentHandle.action: unknown action "' + name + '"');
|
|
11608
12302
|
return;
|
|
11609
12303
|
}
|
|
11610
12304
|
var args = [this].concat(Array.prototype.slice.call(arguments, 1));
|
|
@@ -11616,7 +12310,7 @@
|
|
|
11616
12310
|
* @param {string} sel - CSS selector
|
|
11617
12311
|
* @returns {Element|null}
|
|
11618
12312
|
*/
|
|
11619
|
-
|
|
12313
|
+
_chp.select = function (sel) {
|
|
11620
12314
|
return this.element ? this.element.querySelector(sel) : null;
|
|
11621
12315
|
};
|
|
11622
12316
|
|
|
@@ -11625,7 +12319,7 @@
|
|
|
11625
12319
|
* @param {string} sel - CSS selector
|
|
11626
12320
|
* @returns {Element[]}
|
|
11627
12321
|
*/
|
|
11628
|
-
|
|
12322
|
+
_chp.selectAll = function (sel) {
|
|
11629
12323
|
if (!this.element) return [];
|
|
11630
12324
|
return Array.prototype.slice.call(this.element.querySelectorAll(sel));
|
|
11631
12325
|
};
|
|
@@ -11636,7 +12330,7 @@
|
|
|
11636
12330
|
* @param {string} tag - User-defined identifier (e.g. 'dashboard_prod_east')
|
|
11637
12331
|
* @returns {ComponentHandle} this (for chaining)
|
|
11638
12332
|
*/
|
|
11639
|
-
|
|
12333
|
+
_chp.userTag = function (tag) {
|
|
11640
12334
|
this._userTag = tag;
|
|
11641
12335
|
if (this.element) {
|
|
11642
12336
|
this.element.classList.add(tag);
|
|
@@ -11721,7 +12415,7 @@
|
|
|
11721
12415
|
* and calls the named method. This is the bitwrench equivalent of
|
|
11722
12416
|
* Win32 SendMessage(hwnd, msg, wParam, lParam).
|
|
11723
12417
|
*
|
|
11724
|
-
* @param {string} target - Component UUID (data-bw_comp_id) or user tag (CSS class)
|
|
12418
|
+
* @param {string} target - Component UUID (bw_uuid_*), comp ID (data-bw_comp_id), or user tag (CSS class)
|
|
11725
12419
|
* @param {string} action - Method name to call on the component
|
|
11726
12420
|
* @param {*} data - Data to pass to the method
|
|
11727
12421
|
* @returns {boolean} True if message was dispatched successfully
|
|
@@ -11738,15 +12432,20 @@
|
|
|
11738
12432
|
* };
|
|
11739
12433
|
*/
|
|
11740
12434
|
bw.message = function (target, action, data) {
|
|
11741
|
-
// Try
|
|
11742
|
-
var el = bw
|
|
11743
|
-
|
|
12435
|
+
// Try bw._el() first (handles UUID class, nodeMap cache, getElementById)
|
|
12436
|
+
var el = bw._el(target);
|
|
12437
|
+
// Then try data-bw_comp_id attribute
|
|
12438
|
+
if (!el || !el._bwComponentHandle) {
|
|
12439
|
+
el = bw.$('[data-bw_comp_id="' + target + '"]')[0];
|
|
12440
|
+
}
|
|
12441
|
+
// Then try CSS class (user tag)
|
|
12442
|
+
if (!el || !el._bwComponentHandle) {
|
|
11744
12443
|
el = bw.$('.' + target)[0];
|
|
11745
12444
|
}
|
|
11746
12445
|
if (!el || !el._bwComponentHandle) return false;
|
|
11747
12446
|
var comp = el._bwComponentHandle;
|
|
11748
|
-
if (
|
|
11749
|
-
|
|
12447
|
+
if (!_is(comp[action], 'function')) {
|
|
12448
|
+
_cw('bw.message: unknown action "' + action + '" on component ' + target);
|
|
11750
12449
|
return false;
|
|
11751
12450
|
}
|
|
11752
12451
|
comp[action](data);
|
|
@@ -11754,61 +12453,24 @@
|
|
|
11754
12453
|
};
|
|
11755
12454
|
|
|
11756
12455
|
// ===================================================================================
|
|
11757
|
-
// bw.
|
|
12456
|
+
// bw.apply() / bw.parseJSONFlex() — Server-driven UI protocol
|
|
11758
12457
|
// ===================================================================================
|
|
11759
12458
|
|
|
11760
12459
|
/**
|
|
11761
12460
|
* Registry of named functions sent via register messages.
|
|
11762
|
-
* Populated by
|
|
11763
|
-
* Invoked by
|
|
12461
|
+
* Populated by bw.apply({ type: 'register', name, body }).
|
|
12462
|
+
* Invoked by bw.apply({ type: 'call', name, args }).
|
|
11764
12463
|
* @private
|
|
11765
12464
|
*/
|
|
11766
12465
|
bw._clientFunctions = {};
|
|
11767
12466
|
|
|
11768
12467
|
/**
|
|
11769
|
-
* Whether exec messages are allowed. Set by
|
|
12468
|
+
* Whether exec messages are allowed. Set by bwclient connect opts.allowExec.
|
|
11770
12469
|
* Default false — exec messages are rejected unless explicitly opted in.
|
|
11771
12470
|
* @private
|
|
11772
12471
|
*/
|
|
11773
12472
|
bw._allowExec = false;
|
|
11774
12473
|
|
|
11775
|
-
/**
|
|
11776
|
-
* Built-in client functions available via call() without registration.
|
|
11777
|
-
* @private
|
|
11778
|
-
*/
|
|
11779
|
-
bw._builtinClientFunctions = {
|
|
11780
|
-
scrollTo: function scrollTo(selector) {
|
|
11781
|
-
var el = bw._el(selector);
|
|
11782
|
-
if (el) el.scrollTop = el.scrollHeight;
|
|
11783
|
-
},
|
|
11784
|
-
focus: function focus(selector) {
|
|
11785
|
-
var el = bw._el(selector);
|
|
11786
|
-
if (el && typeof el.focus === 'function') el.focus();
|
|
11787
|
-
},
|
|
11788
|
-
download: function download(filename, content, mimeType) {
|
|
11789
|
-
if (typeof document === 'undefined') return;
|
|
11790
|
-
var blob = new Blob([content], {
|
|
11791
|
-
type: mimeType || 'text/plain'
|
|
11792
|
-
});
|
|
11793
|
-
var a = document.createElement('a');
|
|
11794
|
-
a.href = URL.createObjectURL(blob);
|
|
11795
|
-
a.download = filename;
|
|
11796
|
-
a.click();
|
|
11797
|
-
URL.revokeObjectURL(a.href);
|
|
11798
|
-
},
|
|
11799
|
-
clipboard: function clipboard(text) {
|
|
11800
|
-
if (typeof navigator !== 'undefined' && navigator.clipboard) {
|
|
11801
|
-
navigator.clipboard.writeText(text);
|
|
11802
|
-
}
|
|
11803
|
-
},
|
|
11804
|
-
redirect: function redirect(url) {
|
|
11805
|
-
if (typeof window !== 'undefined') window.location.href = url;
|
|
11806
|
-
},
|
|
11807
|
-
log: function log() {
|
|
11808
|
-
console.log.apply(console, arguments);
|
|
11809
|
-
}
|
|
11810
|
-
};
|
|
11811
|
-
|
|
11812
12474
|
/**
|
|
11813
12475
|
* Parse a bwserve protocol message string, supporting both strict JSON
|
|
11814
12476
|
* and r-prefixed relaxed JSON (single-quoted strings, trailing commas).
|
|
@@ -11823,9 +12485,9 @@
|
|
|
11823
12485
|
* @param {string} str - JSON or r-prefixed relaxed JSON string
|
|
11824
12486
|
* @returns {Object} Parsed message object
|
|
11825
12487
|
* @throws {SyntaxError} If the string is not valid JSON or relaxed JSON
|
|
11826
|
-
* @category
|
|
12488
|
+
* @category Core
|
|
11827
12489
|
*/
|
|
11828
|
-
bw.
|
|
12490
|
+
bw.parseJSONFlex = function (str) {
|
|
11829
12491
|
str = (str || '').trim();
|
|
11830
12492
|
if (str.charAt(0) !== 'r') return JSON.parse(str);
|
|
11831
12493
|
str = str.slice(1);
|
|
@@ -11903,10 +12565,10 @@
|
|
|
11903
12565
|
* append — target.appendChild(bw.createDOM(node))
|
|
11904
12566
|
* remove — bw.cleanup(target); target.remove()
|
|
11905
12567
|
* patch — bw.patch(target, content, attr)
|
|
11906
|
-
* batch — iterate ops, call
|
|
12568
|
+
* batch — iterate ops, call bw.apply for each
|
|
11907
12569
|
* message — bw.message(target, action, data)
|
|
11908
12570
|
* register — store a named function for later call()
|
|
11909
|
-
* call — invoke a registered
|
|
12571
|
+
* call — invoke a registered function
|
|
11910
12572
|
* exec — execute arbitrary JS (requires allowExec)
|
|
11911
12573
|
*
|
|
11912
12574
|
* Target resolution:
|
|
@@ -11915,9 +12577,9 @@
|
|
|
11915
12577
|
*
|
|
11916
12578
|
* @param {Object} msg - Protocol message
|
|
11917
12579
|
* @returns {boolean} true if the message was applied successfully
|
|
11918
|
-
* @category
|
|
12580
|
+
* @category Core
|
|
11919
12581
|
*/
|
|
11920
|
-
bw.
|
|
12582
|
+
bw.apply = function (msg) {
|
|
11921
12583
|
if (!msg || !msg.type) return false;
|
|
11922
12584
|
var type = msg.type;
|
|
11923
12585
|
var target = msg.target;
|
|
@@ -11938,14 +12600,14 @@
|
|
|
11938
12600
|
} else if (type === 'remove') {
|
|
11939
12601
|
var toRemove = bw._el(target);
|
|
11940
12602
|
if (!toRemove) return false;
|
|
11941
|
-
if (
|
|
12603
|
+
if (_is(bw.cleanup, 'function')) bw.cleanup(toRemove);
|
|
11942
12604
|
toRemove.remove();
|
|
11943
12605
|
return true;
|
|
11944
12606
|
} else if (type === 'batch') {
|
|
11945
|
-
if (!
|
|
12607
|
+
if (!_isA(msg.ops)) return false;
|
|
11946
12608
|
var allOk = true;
|
|
11947
12609
|
msg.ops.forEach(function (op) {
|
|
11948
|
-
if (!bw.
|
|
12610
|
+
if (!bw.apply(op)) allOk = false;
|
|
11949
12611
|
});
|
|
11950
12612
|
return allOk;
|
|
11951
12613
|
} else if (type === 'message') {
|
|
@@ -11956,24 +12618,24 @@
|
|
|
11956
12618
|
bw._clientFunctions[msg.name] = new Function('return ' + msg.body)();
|
|
11957
12619
|
return true;
|
|
11958
12620
|
} catch (e) {
|
|
11959
|
-
|
|
12621
|
+
_ce('[bw] register error:', msg.name, e);
|
|
11960
12622
|
return false;
|
|
11961
12623
|
}
|
|
11962
12624
|
} else if (type === 'call') {
|
|
11963
12625
|
if (!msg.name) return false;
|
|
11964
|
-
var fn = bw._clientFunctions[msg.name]
|
|
11965
|
-
if (
|
|
12626
|
+
var fn = bw._clientFunctions[msg.name];
|
|
12627
|
+
if (!_is(fn, 'function')) return false;
|
|
11966
12628
|
try {
|
|
11967
|
-
var args =
|
|
12629
|
+
var args = _isA(msg.args) ? msg.args : [];
|
|
11968
12630
|
fn.apply(null, args);
|
|
11969
12631
|
return true;
|
|
11970
12632
|
} catch (e) {
|
|
11971
|
-
|
|
12633
|
+
_ce('[bw] call error:', msg.name, e);
|
|
11972
12634
|
return false;
|
|
11973
12635
|
}
|
|
11974
12636
|
} else if (type === 'exec') {
|
|
11975
12637
|
if (!bw._allowExec) {
|
|
11976
|
-
|
|
12638
|
+
_cw('[bw] exec rejected: allowExec is not enabled');
|
|
11977
12639
|
return false;
|
|
11978
12640
|
}
|
|
11979
12641
|
if (!msg.code) return false;
|
|
@@ -11981,148 +12643,13 @@
|
|
|
11981
12643
|
new Function(msg.code)();
|
|
11982
12644
|
return true;
|
|
11983
12645
|
} catch (e) {
|
|
11984
|
-
|
|
12646
|
+
_ce('[bw] exec error:', e);
|
|
11985
12647
|
return false;
|
|
11986
12648
|
}
|
|
11987
12649
|
}
|
|
11988
12650
|
return false;
|
|
11989
12651
|
};
|
|
11990
12652
|
|
|
11991
|
-
/**
|
|
11992
|
-
* Connect to a bwserve SSE endpoint and apply protocol messages automatically.
|
|
11993
|
-
*
|
|
11994
|
-
* Returns a connection object with sendAction(), on(), and close() methods.
|
|
11995
|
-
*
|
|
11996
|
-
* @param {string} url - SSE endpoint URL (e.g., '/__bw/events/client-1')
|
|
11997
|
-
* @param {Object} [opts] - Connection options
|
|
11998
|
-
* @param {string} [opts.transport='sse'] - Transport type: 'sse' (default) or 'poll'
|
|
11999
|
-
* @param {number} [opts.interval=2000] - Poll interval in ms (only for 'poll' transport)
|
|
12000
|
-
* @param {string} [opts.actionUrl] - POST endpoint for actions (default: derived from url)
|
|
12001
|
-
* @param {boolean} [opts.reconnect=true] - Auto-reconnect on disconnect
|
|
12002
|
-
* @param {boolean} [opts.allowExec=false] - Enable exec message type (arbitrary JS execution)
|
|
12003
|
-
* @param {Function} [opts.onStatus] - Status callback: 'connecting'|'connected'|'disconnected'
|
|
12004
|
-
* @param {Function} [opts.onMessage] - Raw message callback (before clientApply)
|
|
12005
|
-
* @returns {Object} Connection object { sendAction, on, close, status }
|
|
12006
|
-
* @category Server
|
|
12007
|
-
*/
|
|
12008
|
-
bw.clientConnect = function (url, opts) {
|
|
12009
|
-
opts = opts || {};
|
|
12010
|
-
var transport = opts.transport || 'sse';
|
|
12011
|
-
var actionUrl = opts.actionUrl || url.replace(/\/events\//, '/action/');
|
|
12012
|
-
var reconnect = opts.reconnect !== false;
|
|
12013
|
-
var onStatus = opts.onStatus || function () {};
|
|
12014
|
-
var onMessage = opts.onMessage || null;
|
|
12015
|
-
var handlers = {};
|
|
12016
|
-
// Set the global allowExec flag from connection options
|
|
12017
|
-
bw._allowExec = !!opts.allowExec;
|
|
12018
|
-
var conn = {
|
|
12019
|
-
status: 'connecting',
|
|
12020
|
-
_es: null,
|
|
12021
|
-
_pollTimer: null
|
|
12022
|
-
};
|
|
12023
|
-
function setStatus(s) {
|
|
12024
|
-
conn.status = s;
|
|
12025
|
-
onStatus(s);
|
|
12026
|
-
}
|
|
12027
|
-
function handleMessage(data) {
|
|
12028
|
-
try {
|
|
12029
|
-
var msg = typeof data === 'string' ? bw.clientParse(data) : data;
|
|
12030
|
-
if (onMessage) onMessage(msg);
|
|
12031
|
-
if (handlers.message) handlers.message(msg);
|
|
12032
|
-
bw.clientApply(msg);
|
|
12033
|
-
} catch (e) {
|
|
12034
|
-
if (handlers.error) handlers.error(e);
|
|
12035
|
-
}
|
|
12036
|
-
}
|
|
12037
|
-
if (transport === 'sse' && typeof EventSource !== 'undefined') {
|
|
12038
|
-
setStatus('connecting');
|
|
12039
|
-
var es = new EventSource(url);
|
|
12040
|
-
conn._es = es;
|
|
12041
|
-
es.onopen = function () {
|
|
12042
|
-
setStatus('connected');
|
|
12043
|
-
if (handlers.open) handlers.open();
|
|
12044
|
-
};
|
|
12045
|
-
es.onmessage = function (e) {
|
|
12046
|
-
handleMessage(e.data);
|
|
12047
|
-
};
|
|
12048
|
-
es.onerror = function () {
|
|
12049
|
-
if (conn.status === 'connected') {
|
|
12050
|
-
setStatus('disconnected');
|
|
12051
|
-
}
|
|
12052
|
-
if (handlers.error) handlers.error(new Error('SSE connection error'));
|
|
12053
|
-
if (!reconnect) {
|
|
12054
|
-
es.close();
|
|
12055
|
-
}
|
|
12056
|
-
// EventSource auto-reconnects by default when reconnect=true
|
|
12057
|
-
};
|
|
12058
|
-
} else if (transport === 'poll') {
|
|
12059
|
-
var interval = opts.interval || 2000;
|
|
12060
|
-
setStatus('connected');
|
|
12061
|
-
conn._pollTimer = setInterval(function () {
|
|
12062
|
-
fetch(url).then(function (r) {
|
|
12063
|
-
return r.json();
|
|
12064
|
-
}).then(function (msgs) {
|
|
12065
|
-
if (Array.isArray(msgs)) {
|
|
12066
|
-
msgs.forEach(handleMessage);
|
|
12067
|
-
} else if (msgs && msgs.type) {
|
|
12068
|
-
handleMessage(msgs);
|
|
12069
|
-
}
|
|
12070
|
-
})["catch"](function (e) {
|
|
12071
|
-
if (handlers.error) handlers.error(e);
|
|
12072
|
-
});
|
|
12073
|
-
}, interval);
|
|
12074
|
-
}
|
|
12075
|
-
|
|
12076
|
-
/**
|
|
12077
|
-
* Send an action to the server via POST.
|
|
12078
|
-
* @param {string} action - Action name
|
|
12079
|
-
* @param {Object} [data] - Action payload
|
|
12080
|
-
*/
|
|
12081
|
-
conn.sendAction = function (action, data) {
|
|
12082
|
-
var body = JSON.stringify({
|
|
12083
|
-
type: 'action',
|
|
12084
|
-
action: action,
|
|
12085
|
-
data: data || {}
|
|
12086
|
-
});
|
|
12087
|
-
fetch(actionUrl, {
|
|
12088
|
-
method: 'POST',
|
|
12089
|
-
headers: {
|
|
12090
|
-
'Content-Type': 'application/json'
|
|
12091
|
-
},
|
|
12092
|
-
body: body
|
|
12093
|
-
})["catch"](function (e) {
|
|
12094
|
-
if (handlers.error) handlers.error(e);
|
|
12095
|
-
});
|
|
12096
|
-
};
|
|
12097
|
-
|
|
12098
|
-
/**
|
|
12099
|
-
* Register an event handler.
|
|
12100
|
-
* @param {string} event - 'open'|'message'|'error'|'close'
|
|
12101
|
-
* @param {Function} handler
|
|
12102
|
-
*/
|
|
12103
|
-
conn.on = function (event, handler) {
|
|
12104
|
-
handlers[event] = handler;
|
|
12105
|
-
return conn;
|
|
12106
|
-
};
|
|
12107
|
-
|
|
12108
|
-
/**
|
|
12109
|
-
* Close the connection.
|
|
12110
|
-
*/
|
|
12111
|
-
conn.close = function () {
|
|
12112
|
-
if (conn._es) {
|
|
12113
|
-
conn._es.close();
|
|
12114
|
-
conn._es = null;
|
|
12115
|
-
}
|
|
12116
|
-
if (conn._pollTimer) {
|
|
12117
|
-
clearInterval(conn._pollTimer);
|
|
12118
|
-
conn._pollTimer = null;
|
|
12119
|
-
}
|
|
12120
|
-
setStatus('disconnected');
|
|
12121
|
-
if (handlers.close) handlers.close();
|
|
12122
|
-
};
|
|
12123
|
-
return conn;
|
|
12124
|
-
};
|
|
12125
|
-
|
|
12126
12653
|
// ===================================================================================
|
|
12127
12654
|
// bw.inspect() — Debug utility
|
|
12128
12655
|
// ===================================================================================
|
|
@@ -12149,20 +12676,20 @@
|
|
|
12149
12676
|
el = target.element;
|
|
12150
12677
|
comp = target;
|
|
12151
12678
|
} else {
|
|
12152
|
-
if (
|
|
12679
|
+
if (_is(target, 'string')) {
|
|
12153
12680
|
el = bw.$(target)[0];
|
|
12154
12681
|
}
|
|
12155
12682
|
if (!el) {
|
|
12156
|
-
|
|
12683
|
+
_cw('bw.inspect: element not found');
|
|
12157
12684
|
return null;
|
|
12158
12685
|
}
|
|
12159
12686
|
comp = el._bwComponentHandle;
|
|
12160
12687
|
}
|
|
12161
12688
|
if (!comp) {
|
|
12162
|
-
|
|
12163
|
-
|
|
12164
|
-
|
|
12165
|
-
|
|
12689
|
+
_cl('bw.inspect: no ComponentHandle on this element');
|
|
12690
|
+
_cl(' Tag:', el.tagName);
|
|
12691
|
+
_cl(' Classes:', el.className);
|
|
12692
|
+
_cl(' _bw_state:', el._bw_state || '(none)');
|
|
12166
12693
|
return null;
|
|
12167
12694
|
}
|
|
12168
12695
|
var deps = comp._bindings.reduce(function (s, b) {
|
|
@@ -12171,13 +12698,13 @@
|
|
|
12171
12698
|
return a.indexOf(v) === i;
|
|
12172
12699
|
});
|
|
12173
12700
|
console.group('Component: ' + comp._bwId);
|
|
12174
|
-
|
|
12175
|
-
|
|
12176
|
-
|
|
12177
|
-
|
|
12178
|
-
|
|
12179
|
-
|
|
12180
|
-
|
|
12701
|
+
_cl('State:', comp._state);
|
|
12702
|
+
_cl('Bindings:', comp._bindings.length, '(deps:', deps, ')');
|
|
12703
|
+
_cl('Methods:', _keys(comp._methods));
|
|
12704
|
+
_cl('Actions:', _keys(comp._actions));
|
|
12705
|
+
_cl('User tag:', comp._userTag || '(none)');
|
|
12706
|
+
_cl('Mounted:', comp.mounted);
|
|
12707
|
+
_cl('Element:', comp.element);
|
|
12181
12708
|
console.groupEnd();
|
|
12182
12709
|
return comp;
|
|
12183
12710
|
};
|
|
@@ -12200,8 +12727,8 @@
|
|
|
12200
12727
|
// Pre-extract all binding expressions
|
|
12201
12728
|
var precompiled = [];
|
|
12202
12729
|
function walkExpressions(node) {
|
|
12203
|
-
if (!
|
|
12204
|
-
if (
|
|
12730
|
+
if (!_is(node, 'object')) return;
|
|
12731
|
+
if (_is(node.c, 'string') && node.c.indexOf('${') >= 0) {
|
|
12205
12732
|
var parsed = bw._parseBindings(node.c);
|
|
12206
12733
|
for (var i = 0; i < parsed.length; i++) {
|
|
12207
12734
|
try {
|
|
@@ -12221,9 +12748,9 @@
|
|
|
12221
12748
|
}
|
|
12222
12749
|
if (node.a) {
|
|
12223
12750
|
for (var key in node.a) {
|
|
12224
|
-
if (
|
|
12751
|
+
if (_hop.call(node.a, key)) {
|
|
12225
12752
|
var v = node.a[key];
|
|
12226
|
-
if (
|
|
12753
|
+
if (_is(v, 'string') && v.indexOf('${') >= 0) {
|
|
12227
12754
|
var parsed2 = bw._parseBindings(v);
|
|
12228
12755
|
for (var j = 0; j < parsed2.length; j++) {
|
|
12229
12756
|
try {
|
|
@@ -12244,9 +12771,9 @@
|
|
|
12244
12771
|
}
|
|
12245
12772
|
}
|
|
12246
12773
|
}
|
|
12247
|
-
if (
|
|
12774
|
+
if (_isA(node.c)) {
|
|
12248
12775
|
for (var k = 0; k < node.c.length; k++) walkExpressions(node.c[k]);
|
|
12249
|
-
} else if (
|
|
12776
|
+
} else if (_is(node.c, 'object') && node.c.t) {
|
|
12250
12777
|
walkExpressions(node.c);
|
|
12251
12778
|
}
|
|
12252
12779
|
}
|
|
@@ -12257,7 +12784,7 @@
|
|
|
12257
12784
|
handle._precompiledBindings = precompiled;
|
|
12258
12785
|
if (initialState) {
|
|
12259
12786
|
for (var k in initialState) {
|
|
12260
|
-
if (
|
|
12787
|
+
if (_hop.call(initialState, k)) {
|
|
12261
12788
|
handle._state[k] = initialState[k];
|
|
12262
12789
|
}
|
|
12263
12790
|
}
|
|
@@ -12291,21 +12818,21 @@
|
|
|
12291
12818
|
minify = _options$minify === void 0 ? false : _options$minify,
|
|
12292
12819
|
_options$pretty = options.pretty,
|
|
12293
12820
|
pretty = _options$pretty === void 0 ? !minify : _options$pretty;
|
|
12294
|
-
if (
|
|
12821
|
+
if (_is(rules, 'string')) return rules;
|
|
12295
12822
|
var css = '';
|
|
12296
12823
|
var indent = pretty ? ' ' : '';
|
|
12297
12824
|
var newline = pretty ? '\n' : '';
|
|
12298
12825
|
var space = pretty ? ' ' : '';
|
|
12299
|
-
if (
|
|
12826
|
+
if (_isA(rules)) {
|
|
12300
12827
|
css = rules.map(function (rule) {
|
|
12301
12828
|
return bw.css(rule, options);
|
|
12302
12829
|
}).join(newline);
|
|
12303
|
-
} else if (
|
|
12830
|
+
} else if (_is(rules, 'object')) {
|
|
12304
12831
|
Object.entries(rules).forEach(function (_ref5) {
|
|
12305
12832
|
var _ref6 = _slicedToArray(_ref5, 2),
|
|
12306
12833
|
selector = _ref6[0],
|
|
12307
12834
|
styles = _ref6[1];
|
|
12308
|
-
if (
|
|
12835
|
+
if (_is(styles, 'object')) {
|
|
12309
12836
|
// Handle @media, @keyframes, @supports — recurse into nested block
|
|
12310
12837
|
if (selector.charAt(0) === '@') {
|
|
12311
12838
|
var inner = bw.css(styles, options);
|
|
@@ -12351,7 +12878,7 @@
|
|
|
12351
12878
|
* @returns {Element} The style element
|
|
12352
12879
|
* @category CSS & Styling
|
|
12353
12880
|
* @see bw.css
|
|
12354
|
-
* @see bw.
|
|
12881
|
+
* @see bw.loadStyles
|
|
12355
12882
|
* @example
|
|
12356
12883
|
* bw.injectCSS('.my-class { color: red; }');
|
|
12357
12884
|
* bw.injectCSS({ '.card': { padding: '1rem' } }, { id: 'card-styles' });
|
|
@@ -12359,7 +12886,7 @@
|
|
|
12359
12886
|
bw.injectCSS = function (css) {
|
|
12360
12887
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
12361
12888
|
if (!bw._isBrowser) {
|
|
12362
|
-
|
|
12889
|
+
_cw('bw.injectCSS requires a DOM environment');
|
|
12363
12890
|
return null;
|
|
12364
12891
|
}
|
|
12365
12892
|
var _options$id = options.id,
|
|
@@ -12377,7 +12904,7 @@
|
|
|
12377
12904
|
}
|
|
12378
12905
|
|
|
12379
12906
|
// Convert CSS if needed
|
|
12380
|
-
var cssStr =
|
|
12907
|
+
var cssStr = _is(css, 'string') ? css : bw.css(css, options);
|
|
12381
12908
|
|
|
12382
12909
|
// Set or append CSS
|
|
12383
12910
|
if (append && styleEl.textContent) {
|
|
@@ -12397,230 +12924,19 @@
|
|
|
12397
12924
|
* @param {...Object} styles - Style objects to merge (left-to-right)
|
|
12398
12925
|
* @returns {Object} Merged style object
|
|
12399
12926
|
* @category CSS & Styling
|
|
12400
|
-
* @see bw.u
|
|
12401
12927
|
* @example
|
|
12402
|
-
* var style = bw.s(
|
|
12928
|
+
* var style = bw.s({ display: 'flex' }, { gap: '1rem' }, { color: 'red' });
|
|
12403
12929
|
* // => { display: 'flex', gap: '1rem', color: 'red' }
|
|
12404
12930
|
*/
|
|
12405
12931
|
bw.s = function () {
|
|
12406
12932
|
var result = {};
|
|
12407
12933
|
for (var i = 0; i < arguments.length; i++) {
|
|
12408
12934
|
var arg = arguments[i];
|
|
12409
|
-
if (
|
|
12935
|
+
if (_is(arg, 'object')) Object.assign(result, arg);
|
|
12410
12936
|
}
|
|
12411
12937
|
return result;
|
|
12412
12938
|
};
|
|
12413
12939
|
|
|
12414
|
-
/**
|
|
12415
|
-
* Pre-built CSS utility objects (like Tailwind utilities, but in JS).
|
|
12416
|
-
*
|
|
12417
|
-
* Compose with `bw.s()` to build inline styles without writing raw CSS strings.
|
|
12418
|
-
* Includes flex, padding, margin, typography, color, border, and transition utilities.
|
|
12419
|
-
*
|
|
12420
|
-
* @category CSS & Styling
|
|
12421
|
-
* @see bw.s
|
|
12422
|
-
* @example
|
|
12423
|
-
* { t: 'div', a: { style: bw.s(bw.u.flex, bw.u.gap4, bw.u.p4) },
|
|
12424
|
-
* c: 'Flexbox with 1rem gap and padding' }
|
|
12425
|
-
*/
|
|
12426
|
-
bw.u = {
|
|
12427
|
-
// Display
|
|
12428
|
-
flex: {
|
|
12429
|
-
display: 'flex'
|
|
12430
|
-
},
|
|
12431
|
-
flexCol: {
|
|
12432
|
-
display: 'flex',
|
|
12433
|
-
flexDirection: 'column'
|
|
12434
|
-
},
|
|
12435
|
-
flexRow: {
|
|
12436
|
-
display: 'flex',
|
|
12437
|
-
flexDirection: 'row'
|
|
12438
|
-
},
|
|
12439
|
-
flexWrap: {
|
|
12440
|
-
display: 'flex',
|
|
12441
|
-
flexWrap: 'wrap'
|
|
12442
|
-
},
|
|
12443
|
-
block: {
|
|
12444
|
-
display: 'block'
|
|
12445
|
-
},
|
|
12446
|
-
inline: {
|
|
12447
|
-
display: 'inline'
|
|
12448
|
-
},
|
|
12449
|
-
hidden: {
|
|
12450
|
-
display: 'none'
|
|
12451
|
-
},
|
|
12452
|
-
// Flex alignment
|
|
12453
|
-
justifyCenter: {
|
|
12454
|
-
justifyContent: 'center'
|
|
12455
|
-
},
|
|
12456
|
-
justifyBetween: {
|
|
12457
|
-
justifyContent: 'space-between'
|
|
12458
|
-
},
|
|
12459
|
-
justifyEnd: {
|
|
12460
|
-
justifyContent: 'flex-end'
|
|
12461
|
-
},
|
|
12462
|
-
alignCenter: {
|
|
12463
|
-
alignItems: 'center'
|
|
12464
|
-
},
|
|
12465
|
-
alignStart: {
|
|
12466
|
-
alignItems: 'flex-start'
|
|
12467
|
-
},
|
|
12468
|
-
alignEnd: {
|
|
12469
|
-
alignItems: 'flex-end'
|
|
12470
|
-
},
|
|
12471
|
-
// Gap (0.25rem increments)
|
|
12472
|
-
gap1: {
|
|
12473
|
-
gap: '0.25rem'
|
|
12474
|
-
},
|
|
12475
|
-
gap2: {
|
|
12476
|
-
gap: '0.5rem'
|
|
12477
|
-
},
|
|
12478
|
-
gap3: {
|
|
12479
|
-
gap: '0.75rem'
|
|
12480
|
-
},
|
|
12481
|
-
gap4: {
|
|
12482
|
-
gap: '1rem'
|
|
12483
|
-
},
|
|
12484
|
-
gap6: {
|
|
12485
|
-
gap: '1.5rem'
|
|
12486
|
-
},
|
|
12487
|
-
gap8: {
|
|
12488
|
-
gap: '2rem'
|
|
12489
|
-
},
|
|
12490
|
-
// Padding
|
|
12491
|
-
p0: {
|
|
12492
|
-
padding: '0'
|
|
12493
|
-
},
|
|
12494
|
-
p1: {
|
|
12495
|
-
padding: '0.25rem'
|
|
12496
|
-
},
|
|
12497
|
-
p2: {
|
|
12498
|
-
padding: '0.5rem'
|
|
12499
|
-
},
|
|
12500
|
-
p3: {
|
|
12501
|
-
padding: '0.75rem'
|
|
12502
|
-
},
|
|
12503
|
-
p4: {
|
|
12504
|
-
padding: '1rem'
|
|
12505
|
-
},
|
|
12506
|
-
p6: {
|
|
12507
|
-
padding: '1.5rem'
|
|
12508
|
-
},
|
|
12509
|
-
p8: {
|
|
12510
|
-
padding: '2rem'
|
|
12511
|
-
},
|
|
12512
|
-
px4: {
|
|
12513
|
-
paddingLeft: '1rem',
|
|
12514
|
-
paddingRight: '1rem'
|
|
12515
|
-
},
|
|
12516
|
-
py2: {
|
|
12517
|
-
paddingTop: '0.5rem',
|
|
12518
|
-
paddingBottom: '0.5rem'
|
|
12519
|
-
},
|
|
12520
|
-
py4: {
|
|
12521
|
-
paddingTop: '1rem',
|
|
12522
|
-
paddingBottom: '1rem'
|
|
12523
|
-
},
|
|
12524
|
-
// Margin (same scale)
|
|
12525
|
-
m0: {
|
|
12526
|
-
margin: '0'
|
|
12527
|
-
},
|
|
12528
|
-
m4: {
|
|
12529
|
-
margin: '1rem'
|
|
12530
|
-
},
|
|
12531
|
-
mt2: {
|
|
12532
|
-
marginTop: '0.5rem'
|
|
12533
|
-
},
|
|
12534
|
-
mt4: {
|
|
12535
|
-
marginTop: '1rem'
|
|
12536
|
-
},
|
|
12537
|
-
mb2: {
|
|
12538
|
-
marginBottom: '0.5rem'
|
|
12539
|
-
},
|
|
12540
|
-
mb4: {
|
|
12541
|
-
marginBottom: '1rem'
|
|
12542
|
-
},
|
|
12543
|
-
mx_auto: {
|
|
12544
|
-
marginLeft: 'auto',
|
|
12545
|
-
marginRight: 'auto'
|
|
12546
|
-
},
|
|
12547
|
-
// Typography
|
|
12548
|
-
textSm: {
|
|
12549
|
-
fontSize: '0.875rem'
|
|
12550
|
-
},
|
|
12551
|
-
textBase: {
|
|
12552
|
-
fontSize: '1rem'
|
|
12553
|
-
},
|
|
12554
|
-
textLg: {
|
|
12555
|
-
fontSize: '1.125rem'
|
|
12556
|
-
},
|
|
12557
|
-
textXl: {
|
|
12558
|
-
fontSize: '1.25rem'
|
|
12559
|
-
},
|
|
12560
|
-
text2xl: {
|
|
12561
|
-
fontSize: '1.5rem'
|
|
12562
|
-
},
|
|
12563
|
-
text3xl: {
|
|
12564
|
-
fontSize: '1.875rem'
|
|
12565
|
-
},
|
|
12566
|
-
bold: {
|
|
12567
|
-
fontWeight: '700'
|
|
12568
|
-
},
|
|
12569
|
-
semibold: {
|
|
12570
|
-
fontWeight: '600'
|
|
12571
|
-
},
|
|
12572
|
-
italic: {
|
|
12573
|
-
fontStyle: 'italic'
|
|
12574
|
-
},
|
|
12575
|
-
textCenter: {
|
|
12576
|
-
textAlign: 'center'
|
|
12577
|
-
},
|
|
12578
|
-
textRight: {
|
|
12579
|
-
textAlign: 'right'
|
|
12580
|
-
},
|
|
12581
|
-
// Colors (from design tokens)
|
|
12582
|
-
bgWhite: {
|
|
12583
|
-
background: '#ffffff'
|
|
12584
|
-
},
|
|
12585
|
-
bgTeal: {
|
|
12586
|
-
background: '#006666',
|
|
12587
|
-
color: '#ffffff'
|
|
12588
|
-
},
|
|
12589
|
-
textWhite: {
|
|
12590
|
-
color: '#ffffff'
|
|
12591
|
-
},
|
|
12592
|
-
textTeal: {
|
|
12593
|
-
color: '#006666'
|
|
12594
|
-
},
|
|
12595
|
-
textMuted: {
|
|
12596
|
-
color: '#888'
|
|
12597
|
-
},
|
|
12598
|
-
// Borders
|
|
12599
|
-
rounded: {
|
|
12600
|
-
borderRadius: '0.375rem'
|
|
12601
|
-
},
|
|
12602
|
-
roundedLg: {
|
|
12603
|
-
borderRadius: '0.5rem'
|
|
12604
|
-
},
|
|
12605
|
-
roundedFull: {
|
|
12606
|
-
borderRadius: '9999px'
|
|
12607
|
-
},
|
|
12608
|
-
border: {
|
|
12609
|
-
border: '1px solid #d8d8d8'
|
|
12610
|
-
},
|
|
12611
|
-
// Sizing
|
|
12612
|
-
wFull: {
|
|
12613
|
-
width: '100%'
|
|
12614
|
-
},
|
|
12615
|
-
hFull: {
|
|
12616
|
-
height: '100%'
|
|
12617
|
-
},
|
|
12618
|
-
// Transitions
|
|
12619
|
-
transition: {
|
|
12620
|
-
transition: 'all 0.2s ease'
|
|
12621
|
-
}
|
|
12622
|
-
};
|
|
12623
|
-
|
|
12624
12940
|
/**
|
|
12625
12941
|
* Generate responsive CSS with media query breakpoints.
|
|
12626
12942
|
*
|
|
@@ -12651,7 +12967,7 @@
|
|
|
12651
12967
|
xl: '1200px'
|
|
12652
12968
|
};
|
|
12653
12969
|
var parts = [];
|
|
12654
|
-
|
|
12970
|
+
_keys(breakpoints).forEach(function (key) {
|
|
12655
12971
|
var rules = {};
|
|
12656
12972
|
if (key === 'base') {
|
|
12657
12973
|
rules[selector] = breakpoints[key];
|
|
@@ -12723,18 +13039,18 @@
|
|
|
12723
13039
|
if (!selector) return [];
|
|
12724
13040
|
|
|
12725
13041
|
// Already an array
|
|
12726
|
-
if (
|
|
13042
|
+
if (_isA(selector)) return selector;
|
|
12727
13043
|
|
|
12728
13044
|
// Single element
|
|
12729
13045
|
if (selector.nodeType) return [selector];
|
|
12730
13046
|
|
|
12731
13047
|
// NodeList or HTMLCollection
|
|
12732
|
-
if (selector.length !== undefined &&
|
|
13048
|
+
if (selector.length !== undefined && !_is(selector, 'string')) {
|
|
12733
13049
|
return Array.from(selector);
|
|
12734
13050
|
}
|
|
12735
13051
|
|
|
12736
13052
|
// CSS selector string
|
|
12737
|
-
if (
|
|
13053
|
+
if (_is(selector, 'string')) {
|
|
12738
13054
|
return Array.from(document.querySelectorAll(selector));
|
|
12739
13055
|
}
|
|
12740
13056
|
return [];
|
|
@@ -12746,111 +13062,48 @@
|
|
|
12746
13062
|
};
|
|
12747
13063
|
}
|
|
12748
13064
|
|
|
13065
|
+
// =========================================================================
|
|
13066
|
+
// v2.0.18 Clean Styles API — makeStyles / applyStyles / loadStyles / etc.
|
|
13067
|
+
// =========================================================================
|
|
13068
|
+
|
|
12749
13069
|
/**
|
|
12750
|
-
*
|
|
12751
|
-
*
|
|
12752
|
-
*
|
|
12753
|
-
*
|
|
12754
|
-
* Returns null in Node.js (no DOM).
|
|
12755
|
-
*
|
|
12756
|
-
* @param {Object} [options] - Style loading options
|
|
12757
|
-
* @param {boolean} [options.minify=true] - Minify the CSS output
|
|
12758
|
-
* @returns {Element|null} Style element if in browser, null in Node.js
|
|
12759
|
-
* @category CSS & Styling
|
|
12760
|
-
* @see bw.setTheme
|
|
12761
|
-
* @see bw.applyTheme
|
|
12762
|
-
* @see bw.toggleTheme
|
|
12763
|
-
* @example
|
|
12764
|
-
* bw.loadDefaultStyles(); // inject all default CSS
|
|
13070
|
+
* Convert a scope selector to a <style> element id.
|
|
13071
|
+
* @private
|
|
13072
|
+
* @param {string} [scope] - Scope selector (e.g. '#my-dashboard', '.preview')
|
|
13073
|
+
* @returns {string} Style element id (e.g. 'bw_style_my_dashboard')
|
|
12765
13074
|
*/
|
|
12766
|
-
|
|
12767
|
-
|
|
12768
|
-
|
|
12769
|
-
|
|
12770
|
-
|
|
12771
|
-
|
|
12772
|
-
|
|
12773
|
-
if (bw._isBrowser) {
|
|
12774
|
-
var structuralCSS = bw.css(getStructuralStyles());
|
|
12775
|
-
bw.injectCSS(structuralCSS, {
|
|
12776
|
-
id: 'bw_structural',
|
|
12777
|
-
append: false,
|
|
12778
|
-
minify: minify
|
|
12779
|
-
});
|
|
12780
|
-
}
|
|
12781
|
-
|
|
12782
|
-
// 2. Inject cosmetic CSS via generateTheme (colors, shadows, radii)
|
|
12783
|
-
var paletteConfig = Object.assign({}, DEFAULT_PALETTE_CONFIG, palette || {});
|
|
12784
|
-
var result = bw.generateTheme('', Object.assign({}, paletteConfig, {
|
|
12785
|
-
inject: true
|
|
12786
|
-
}));
|
|
12787
|
-
return result;
|
|
12788
|
-
};
|
|
13075
|
+
function _scopeToStyleId(scope) {
|
|
13076
|
+
if (!scope || scope === '' || scope === 'global') return 'bw_style_global';
|
|
13077
|
+
if (scope === 'reset') return 'bw_style_reset';
|
|
13078
|
+
// Strip leading # or . and convert - to _
|
|
13079
|
+
var clean = scope.replace(/^[#.]/, '').replace(/-/g, '_');
|
|
13080
|
+
return 'bw_style_' + clean;
|
|
13081
|
+
}
|
|
12789
13082
|
|
|
12790
13083
|
/**
|
|
12791
|
-
* Generate a complete
|
|
12792
|
-
*
|
|
12793
|
-
*
|
|
12794
|
-
*
|
|
12795
|
-
*
|
|
12796
|
-
*
|
|
12797
|
-
*
|
|
12798
|
-
* @param {string}
|
|
12799
|
-
* @param {
|
|
12800
|
-
* @param {string} config.primary - Primary brand color hex
|
|
12801
|
-
* @param {string} config.secondary - Secondary color hex
|
|
12802
|
-
* @param {string} [config.tertiary] - Tertiary/accent color hex (defaults to primary)
|
|
12803
|
-
* @param {string} [config.success='#198754'] - Success color hex
|
|
12804
|
-
* @param {string} [config.danger='#dc3545'] - Danger color hex
|
|
12805
|
-
* @param {string} [config.warning='#ffc107'] - Warning color hex
|
|
12806
|
-
* @param {string} [config.info='#0dcaf0'] - Info color hex
|
|
12807
|
-
* @param {string} [config.light='#f8f9fa'] - Light color hex
|
|
12808
|
-
* @param {string} [config.dark='#212529'] - Dark color hex
|
|
12809
|
-
* @param {string} [config.background] - Page background hex (default: '#ffffff' light, derived dark)
|
|
12810
|
-
* @param {string} [config.surface] - Surface/card background hex (default: '#f8f9fa' light, derived dark)
|
|
13084
|
+
* Generate a complete styles object from seed colors and layout config.
|
|
13085
|
+
* Pure function — no DOM, no state, no side effects.
|
|
13086
|
+
*
|
|
13087
|
+
* All parameters are optional. Defaults to the bitwrench default palette.
|
|
13088
|
+
*
|
|
13089
|
+
* @param {Object} [config] - Style configuration
|
|
13090
|
+
* @param {string} [config.primary='#006666'] - Primary brand color hex
|
|
13091
|
+
* @param {string} [config.secondary='#6c757d'] - Secondary color hex
|
|
13092
|
+
* @param {string} [config.tertiary] - Tertiary color hex (defaults to primary)
|
|
12811
13093
|
* @param {string} [config.spacing='normal'] - 'compact' | 'normal' | 'spacious'
|
|
12812
13094
|
* @param {string} [config.radius='md'] - 'none' | 'sm' | 'md' | 'lg' | 'pill'
|
|
12813
|
-
* @
|
|
12814
|
-
* @param {string|number} [config.typeRatio='normal'] - 'tight' | 'normal' | 'relaxed' | 'dramatic' or a number
|
|
12815
|
-
* @param {string} [config.elevation='md'] - 'flat' | 'sm' | 'md' | 'lg'
|
|
12816
|
-
* @param {string} [config.motion='standard'] - 'reduced' | 'standard' | 'expressive'
|
|
12817
|
-
* @param {number} [config.harmonize=0.20] - 0-1, semantic color hue shift toward primary
|
|
12818
|
-
* @param {boolean} [config.inject=true] - Inject into DOM (browser only)
|
|
12819
|
-
* @returns {Object} { css, palette, name, isLightPrimary, alternate: { css, palette } }
|
|
13095
|
+
* @returns {Object} { css, alternateCss, rules, alternateRules, palette, alternatePalette, isLightPrimary }
|
|
12820
13096
|
* @category CSS & Styling
|
|
12821
|
-
* @see bw.
|
|
12822
|
-
* @see bw.
|
|
12823
|
-
* @see bw.loadDefaultStyles
|
|
13097
|
+
* @see bw.applyStyles
|
|
13098
|
+
* @see bw.loadStyles
|
|
12824
13099
|
* @example
|
|
12825
|
-
*
|
|
12826
|
-
*
|
|
12827
|
-
*
|
|
12828
|
-
* secondary: '#90e0ef',
|
|
12829
|
-
* tertiary: '#00b4d8'
|
|
12830
|
-
* });
|
|
12831
|
-
*
|
|
12832
|
-
* // Apply to a container
|
|
12833
|
-
* document.getElementById('app').classList.add('ocean');
|
|
12834
|
-
*
|
|
12835
|
-
* // Toggle to alternate palette
|
|
12836
|
-
* bw.toggleTheme();
|
|
12837
|
-
*
|
|
12838
|
-
* // Generate CSS for static export (Node.js)
|
|
12839
|
-
* var result = bw.generateTheme('sunset', {
|
|
12840
|
-
* primary: '#e76f51',
|
|
12841
|
-
* secondary: '#264653',
|
|
12842
|
-
* inject: false
|
|
12843
|
-
* });
|
|
12844
|
-
* fs.writeFileSync('sunset.css', result.css + result.alternate.css);
|
|
13100
|
+
* var styles = bw.makeStyles({ primary: '#4f46e5', secondary: '#d97706' });
|
|
13101
|
+
* console.log(styles.palette.primary.base); // '#4f46e5'
|
|
13102
|
+
* // styles.css contains all themed CSS — nothing injected
|
|
12845
13103
|
*/
|
|
12846
|
-
bw.
|
|
12847
|
-
|
|
12848
|
-
|
|
12849
|
-
}
|
|
12850
|
-
|
|
12851
|
-
// Merge with defaults; if user didn't supply tertiary, default to their primary
|
|
12852
|
-
var fullConfig = Object.assign({}, DEFAULT_PALETTE_CONFIG, config);
|
|
12853
|
-
if (!config.tertiary) fullConfig.tertiary = fullConfig.primary;
|
|
13104
|
+
bw.makeStyles = function (config) {
|
|
13105
|
+
var fullConfig = Object.assign({}, DEFAULT_PALETTE_CONFIG, config || {});
|
|
13106
|
+
if (config && !config.tertiary) fullConfig.tertiary = fullConfig.primary;
|
|
12854
13107
|
|
|
12855
13108
|
// Derive primary palette
|
|
12856
13109
|
var palette = derivePalette(fullConfig);
|
|
@@ -12858,136 +13111,211 @@
|
|
|
12858
13111
|
// Resolve layout
|
|
12859
13112
|
var layout = resolveLayout(fullConfig);
|
|
12860
13113
|
|
|
12861
|
-
// Generate primary themed CSS rules
|
|
12862
|
-
var themedRules = generateThemedCSS(
|
|
13114
|
+
// Generate primary themed CSS rules (unscoped)
|
|
13115
|
+
var themedRules = generateThemedCSS('', palette, layout);
|
|
12863
13116
|
var cssStr = bw.css(themedRules);
|
|
12864
13117
|
|
|
12865
13118
|
// Derive alternate palette (luminance-inverted)
|
|
12866
13119
|
var altConfig = deriveAlternateConfig(fullConfig);
|
|
12867
13120
|
var altPalette = derivePalette(altConfig);
|
|
12868
13121
|
|
|
12869
|
-
// Generate alternate CSS
|
|
12870
|
-
|
|
12871
|
-
var
|
|
13122
|
+
// Generate alternate CSS rules WITHOUT .bw_theme_alt prefix (raw rules)
|
|
13123
|
+
// applyStyles() wraps them appropriately based on scope
|
|
13124
|
+
var altRawRules = generateThemedCSS('', altPalette, layout);
|
|
13125
|
+
|
|
13126
|
+
// Add body-level surface overrides for the alternate palette.
|
|
13127
|
+
// When .bw_theme_alt is on <html>, ".bw_theme_alt body" correctly matches.
|
|
13128
|
+
altRawRules['body'] = {
|
|
13129
|
+
'color': altPalette.dark.base,
|
|
13130
|
+
'background-color': altPalette.surface || altPalette.light.base
|
|
13131
|
+
};
|
|
13132
|
+
var altCssStr = bw.css(altRawRules);
|
|
12872
13133
|
|
|
12873
13134
|
// Determine if primary is light-flavored
|
|
12874
13135
|
var lightPrimary = isLightPalette(fullConfig);
|
|
13136
|
+
return {
|
|
13137
|
+
css: cssStr,
|
|
13138
|
+
alternateCss: altCssStr,
|
|
13139
|
+
rules: themedRules,
|
|
13140
|
+
alternateRules: altRawRules,
|
|
13141
|
+
palette: palette,
|
|
13142
|
+
alternatePalette: altPalette,
|
|
13143
|
+
isLightPrimary: lightPrimary
|
|
13144
|
+
};
|
|
13145
|
+
};
|
|
12875
13146
|
|
|
12876
|
-
|
|
12877
|
-
|
|
12878
|
-
|
|
12879
|
-
|
|
12880
|
-
|
|
12881
|
-
|
|
12882
|
-
|
|
12883
|
-
|
|
12884
|
-
|
|
12885
|
-
|
|
12886
|
-
|
|
12887
|
-
|
|
12888
|
-
|
|
12889
|
-
|
|
12890
|
-
|
|
13147
|
+
/**
|
|
13148
|
+
* Inject styles into the DOM with optional scoping.
|
|
13149
|
+
*
|
|
13150
|
+
* Takes a styles object from `makeStyles()` and creates a single `<style>`
|
|
13151
|
+
* element in `<head>`. If a scope selector is provided, all CSS rules are
|
|
13152
|
+
* wrapped under that selector. Alternate CSS is wrapped under `.bw_theme_alt`.
|
|
13153
|
+
*
|
|
13154
|
+
* @param {Object} styles - Result of `bw.makeStyles()`
|
|
13155
|
+
* @param {string} [scope] - Scope selector (e.g. '#my-dashboard', '.preview'). Omit for global.
|
|
13156
|
+
* @returns {Element|null} The `<style>` element, or null in Node.js
|
|
13157
|
+
* @category CSS & Styling
|
|
13158
|
+
* @see bw.makeStyles
|
|
13159
|
+
* @see bw.loadStyles
|
|
13160
|
+
* @see bw.clearStyles
|
|
13161
|
+
* @example
|
|
13162
|
+
* var styles = bw.makeStyles({ primary: '#4f46e5' });
|
|
13163
|
+
* bw.applyStyles(styles); // global
|
|
13164
|
+
* bw.applyStyles(styles, '#my-dashboard'); // scoped
|
|
13165
|
+
*/
|
|
13166
|
+
bw.applyStyles = function (styles, scope) {
|
|
13167
|
+
if (!bw._isBrowser) return null;
|
|
13168
|
+
if (!styles || !styles.rules) {
|
|
13169
|
+
_cw('bw.applyStyles: invalid styles object');
|
|
13170
|
+
return null;
|
|
12891
13171
|
}
|
|
13172
|
+
var styleId = _scopeToStyleId(scope);
|
|
12892
13173
|
|
|
12893
|
-
//
|
|
12894
|
-
|
|
12895
|
-
|
|
12896
|
-
|
|
12897
|
-
color: palette.primary.textOn
|
|
12898
|
-
};
|
|
12899
|
-
bw.u.textTeal = {
|
|
12900
|
-
color: palette.primary.base
|
|
12901
|
-
};
|
|
12902
|
-
bw.u.bgWhite = {
|
|
12903
|
-
background: '#ffffff'
|
|
12904
|
-
};
|
|
12905
|
-
bw.u.textWhite = {
|
|
12906
|
-
color: '#ffffff'
|
|
12907
|
-
};
|
|
13174
|
+
// Scope the primary rules if a scope is provided
|
|
13175
|
+
var primaryRules = styles.rules;
|
|
13176
|
+
if (scope) {
|
|
13177
|
+
primaryRules = scopeRulesUnder(primaryRules, scope);
|
|
12908
13178
|
}
|
|
12909
13179
|
|
|
12910
|
-
//
|
|
12911
|
-
var
|
|
12912
|
-
|
|
12913
|
-
|
|
12914
|
-
|
|
12915
|
-
|
|
12916
|
-
|
|
12917
|
-
|
|
12918
|
-
|
|
13180
|
+
// Wrap alternate rules with .bw_theme_alt
|
|
13181
|
+
var altRules = styles.alternateRules;
|
|
13182
|
+
if (altRules) {
|
|
13183
|
+
if (scope) {
|
|
13184
|
+
// Scoped compound: #scope.bw_theme_alt .bw_card
|
|
13185
|
+
altRules = scopeRulesUnder(altRules, scope + '.bw_theme_alt');
|
|
13186
|
+
} else {
|
|
13187
|
+
// Global: .bw_theme_alt .bw_card
|
|
13188
|
+
altRules = scopeRulesUnder(altRules, '.bw_theme_alt');
|
|
12919
13189
|
}
|
|
12920
|
-
}
|
|
12921
|
-
|
|
12922
|
-
|
|
12923
|
-
|
|
13190
|
+
}
|
|
13191
|
+
|
|
13192
|
+
// Combine primary + alternate into one CSS string
|
|
13193
|
+
var combined = bw.css(primaryRules);
|
|
13194
|
+
if (altRules) {
|
|
13195
|
+
combined += '\n' + bw.css(altRules);
|
|
13196
|
+
}
|
|
13197
|
+
return bw.injectCSS(combined, {
|
|
13198
|
+
id: styleId,
|
|
13199
|
+
append: false
|
|
13200
|
+
});
|
|
12924
13201
|
};
|
|
12925
13202
|
|
|
12926
13203
|
/**
|
|
12927
|
-
*
|
|
12928
|
-
*
|
|
13204
|
+
* Generate and apply styles in one call. Convenience wrapper.
|
|
13205
|
+
*
|
|
13206
|
+
* Equivalent to: `bw.applyStyles(bw.makeStyles(config), scope)`
|
|
12929
13207
|
*
|
|
12930
|
-
* @param {
|
|
12931
|
-
* @
|
|
13208
|
+
* @param {Object} [config] - Style configuration (same as `makeStyles`)
|
|
13209
|
+
* @param {string} [scope] - Scope selector (same as `applyStyles`)
|
|
13210
|
+
* @returns {Element|null} The `<style>` element, or null in Node.js
|
|
12932
13211
|
* @category CSS & Styling
|
|
12933
|
-
* @see bw.
|
|
12934
|
-
* @see bw.
|
|
13212
|
+
* @see bw.makeStyles
|
|
13213
|
+
* @see bw.applyStyles
|
|
12935
13214
|
* @example
|
|
12936
|
-
* bw.
|
|
12937
|
-
* bw.
|
|
12938
|
-
* bw.
|
|
12939
|
-
*/
|
|
12940
|
-
bw.
|
|
12941
|
-
|
|
12942
|
-
|
|
12943
|
-
|
|
12944
|
-
|
|
12945
|
-
|
|
12946
|
-
|
|
12947
|
-
|
|
12948
|
-
|
|
12949
|
-
|
|
13215
|
+
* bw.loadStyles(); // defaults, global
|
|
13216
|
+
* bw.loadStyles({ primary: '#4f46e5' }); // custom, global
|
|
13217
|
+
* bw.loadStyles({ primary: '#4f46e5' }, '#my-dashboard'); // custom, scoped
|
|
13218
|
+
*/
|
|
13219
|
+
bw.loadStyles = function (config, scope) {
|
|
13220
|
+
// Also inject structural CSS first (only once)
|
|
13221
|
+
if (bw._isBrowser) {
|
|
13222
|
+
var existing = document.getElementById('bw_structural');
|
|
13223
|
+
if (!existing) {
|
|
13224
|
+
var structuralCSS = bw.css(getStructuralStyles());
|
|
13225
|
+
bw.injectCSS(structuralCSS, {
|
|
13226
|
+
id: 'bw_structural',
|
|
13227
|
+
append: false
|
|
13228
|
+
});
|
|
13229
|
+
}
|
|
12950
13230
|
}
|
|
12951
|
-
bw.
|
|
12952
|
-
|
|
13231
|
+
return bw.applyStyles(bw.makeStyles(config), scope);
|
|
13232
|
+
};
|
|
13233
|
+
|
|
13234
|
+
/**
|
|
13235
|
+
* Inject the CSS reset (box-sizing, html/body font, reduced-motion).
|
|
13236
|
+
* Idempotent — if already injected, returns the existing `<style>` element.
|
|
13237
|
+
*
|
|
13238
|
+
* @returns {Element|null} The `<style>` element, or null in Node.js
|
|
13239
|
+
* @category CSS & Styling
|
|
13240
|
+
* @see bw.loadStyles
|
|
13241
|
+
* @see bw.clearStyles
|
|
13242
|
+
* @example
|
|
13243
|
+
* bw.loadReset(); // inject once, safe to call multiple times
|
|
13244
|
+
*/
|
|
13245
|
+
bw.loadReset = function () {
|
|
13246
|
+
if (!bw._isBrowser) return null;
|
|
13247
|
+
var existing = document.getElementById('bw_style_reset');
|
|
13248
|
+
if (existing) return existing;
|
|
13249
|
+
return bw.injectCSS(bw.css(getResetStyles()), {
|
|
13250
|
+
id: 'bw_style_reset',
|
|
13251
|
+
append: false
|
|
13252
|
+
});
|
|
12953
13253
|
};
|
|
12954
13254
|
|
|
12955
13255
|
/**
|
|
12956
|
-
* Toggle between primary and alternate
|
|
13256
|
+
* Toggle between primary and alternate palettes.
|
|
13257
|
+
*
|
|
13258
|
+
* Adds/removes the `bw_theme_alt` class on the scoping element.
|
|
13259
|
+
* Without a scope, toggles on `<html>` (global).
|
|
13260
|
+
* With a scope, toggles on the first matching element.
|
|
12957
13261
|
*
|
|
13262
|
+
* @param {string} [scope] - Scope selector (e.g. '#my-dashboard'). Omit for global.
|
|
12958
13263
|
* @returns {string} Active mode after toggle: 'primary' or 'alternate'
|
|
12959
13264
|
* @category CSS & Styling
|
|
12960
|
-
* @see bw.
|
|
12961
|
-
* @see bw.
|
|
13265
|
+
* @see bw.applyStyles
|
|
13266
|
+
* @see bw.clearStyles
|
|
12962
13267
|
* @example
|
|
12963
|
-
* bw.
|
|
13268
|
+
* bw.toggleStyles(); // global toggle on <html>
|
|
13269
|
+
* bw.toggleStyles('#my-dashboard'); // scoped toggle
|
|
12964
13270
|
*/
|
|
12965
|
-
bw.
|
|
12966
|
-
|
|
12967
|
-
|
|
13271
|
+
bw.toggleStyles = function (scope) {
|
|
13272
|
+
if (!bw._isBrowser) return 'primary';
|
|
13273
|
+
var target;
|
|
13274
|
+
if (scope) {
|
|
13275
|
+
var els = bw.$(scope);
|
|
13276
|
+
target = els[0];
|
|
13277
|
+
} else {
|
|
13278
|
+
target = document.documentElement;
|
|
13279
|
+
}
|
|
13280
|
+
if (!target) return 'primary';
|
|
13281
|
+
var hasAlt = target.classList.contains('bw_theme_alt');
|
|
13282
|
+
if (hasAlt) {
|
|
13283
|
+
target.classList.remove('bw_theme_alt');
|
|
13284
|
+
return 'primary';
|
|
13285
|
+
} else {
|
|
13286
|
+
target.classList.add('bw_theme_alt');
|
|
13287
|
+
return 'alternate';
|
|
13288
|
+
}
|
|
12968
13289
|
};
|
|
12969
13290
|
|
|
12970
13291
|
/**
|
|
12971
|
-
* Remove
|
|
12972
|
-
* Use this before generating a new theme with a different name to prevent
|
|
12973
|
-
* stale CSS accumulation.
|
|
13292
|
+
* Remove injected styles for a given scope.
|
|
12974
13293
|
*
|
|
13294
|
+
* Finds the `<style>` element by id and removes it. Also removes
|
|
13295
|
+
* the `bw_theme_alt` class from the relevant element.
|
|
13296
|
+
*
|
|
13297
|
+
* @param {string} [scope] - Scope selector. Omit to remove global styles.
|
|
12975
13298
|
* @category CSS & Styling
|
|
12976
|
-
* @see bw.
|
|
13299
|
+
* @see bw.applyStyles
|
|
13300
|
+
* @see bw.loadStyles
|
|
12977
13301
|
* @example
|
|
12978
|
-
* bw.
|
|
12979
|
-
* bw.
|
|
12980
|
-
|
|
12981
|
-
|
|
12982
|
-
|
|
12983
|
-
|
|
12984
|
-
|
|
12985
|
-
|
|
12986
|
-
|
|
12987
|
-
|
|
13302
|
+
* bw.clearStyles(); // remove global styles
|
|
13303
|
+
* bw.clearStyles('#my-dashboard'); // remove scoped styles
|
|
13304
|
+
* bw.clearStyles('reset'); // remove the CSS reset
|
|
13305
|
+
*/
|
|
13306
|
+
bw.clearStyles = function (scope) {
|
|
13307
|
+
if (!bw._isBrowser) return;
|
|
13308
|
+
var styleId = _scopeToStyleId(scope);
|
|
13309
|
+
var el = document.getElementById(styleId);
|
|
13310
|
+
if (el) el.remove();
|
|
13311
|
+
|
|
13312
|
+
// Also remove bw_theme_alt from the relevant element
|
|
13313
|
+
if (scope && scope !== 'reset' && scope !== 'global') {
|
|
13314
|
+
var targets = bw.$(scope);
|
|
13315
|
+
if (targets[0]) targets[0].classList.remove('bw_theme_alt');
|
|
13316
|
+
} else if (!scope || scope === 'global') {
|
|
13317
|
+
document.documentElement.classList.remove('bw_theme_alt');
|
|
12988
13318
|
}
|
|
12989
|
-
bw._activeTheme = null;
|
|
12990
|
-
bw._activeThemeMode = 'primary';
|
|
12991
13319
|
};
|
|
12992
13320
|
|
|
12993
13321
|
// Expose color utility functions on bw namespace
|
|
@@ -13209,10 +13537,15 @@
|
|
|
13209
13537
|
* @param {Object} config - Table configuration
|
|
13210
13538
|
* @param {Array<Object>} config.data - Array of row objects to display
|
|
13211
13539
|
* @param {Array<Object>} [config.columns] - Column definitions with key, label, render
|
|
13212
|
-
* @param {string} [config.className='
|
|
13540
|
+
* @param {string} [config.className=''] - Additional CSS classes for table element
|
|
13213
13541
|
* @param {boolean} [config.sortable=true] - Enable click-to-sort headers
|
|
13214
13542
|
* @param {Function} [config.onSort] - Sort callback (column, direction)
|
|
13215
|
-
* @
|
|
13543
|
+
* @param {boolean} [config.selectable=false] - Enable row selection on click
|
|
13544
|
+
* @param {Function} [config.onRowClick] - Row click callback (row, index, event)
|
|
13545
|
+
* @param {number} [config.pageSize] - Rows per page (enables pagination when set)
|
|
13546
|
+
* @param {number} [config.currentPage=1] - Current page number (1-based)
|
|
13547
|
+
* @param {Function} [config.onPageChange] - Page change callback (newPage)
|
|
13548
|
+
* @returns {Object} TACO object for table (with optional pagination controls)
|
|
13216
13549
|
* @category Component Builders
|
|
13217
13550
|
* @see bw.makeDataTable
|
|
13218
13551
|
* @example
|
|
@@ -13224,7 +13557,12 @@
|
|
|
13224
13557
|
* columns: [
|
|
13225
13558
|
* { key: 'name', label: 'Name' },
|
|
13226
13559
|
* { key: 'age', label: 'Age' }
|
|
13227
|
-
* ]
|
|
13560
|
+
* ],
|
|
13561
|
+
* selectable: true,
|
|
13562
|
+
* onRowClick: function(row, i) { console.log('clicked', row.name); },
|
|
13563
|
+
* pageSize: 10,
|
|
13564
|
+
* currentPage: 1,
|
|
13565
|
+
* onPageChange: function(page) { console.log('page', page); }
|
|
13228
13566
|
* });
|
|
13229
13567
|
*/
|
|
13230
13568
|
bw.makeTable = function (config) {
|
|
@@ -13242,17 +13580,25 @@
|
|
|
13242
13580
|
onSort = config.onSort,
|
|
13243
13581
|
sortColumn = config.sortColumn,
|
|
13244
13582
|
_config$sortDirection = config.sortDirection,
|
|
13245
|
-
sortDirection = _config$sortDirection === void 0 ? 'asc' : _config$sortDirection
|
|
13246
|
-
|
|
13247
|
-
|
|
13583
|
+
sortDirection = _config$sortDirection === void 0 ? 'asc' : _config$sortDirection,
|
|
13584
|
+
_config$selectable = config.selectable,
|
|
13585
|
+
selectable = _config$selectable === void 0 ? false : _config$selectable,
|
|
13586
|
+
onRowClick = config.onRowClick,
|
|
13587
|
+
pageSize = config.pageSize,
|
|
13588
|
+
_config$currentPage = config.currentPage,
|
|
13589
|
+
currentPage = _config$currentPage === void 0 ? 1 : _config$currentPage,
|
|
13590
|
+
onPageChange = config.onPageChange;
|
|
13591
|
+
|
|
13592
|
+
// Build class list: always include bw_table, add striped/hover/selectable, append user className
|
|
13248
13593
|
var cls = 'bw_table';
|
|
13249
13594
|
if (striped) cls += ' bw_table_striped';
|
|
13250
|
-
if (hover) cls += ' bw_table_hover';
|
|
13595
|
+
if (hover || selectable) cls += ' bw_table_hover';
|
|
13596
|
+
if (selectable) cls += ' bw_table_selectable';
|
|
13251
13597
|
if (className) cls += ' ' + className;
|
|
13252
13598
|
cls = cls.trim();
|
|
13253
13599
|
|
|
13254
13600
|
// Auto-detect columns if not provided
|
|
13255
|
-
var cols = columns || (data.length > 0 ?
|
|
13601
|
+
var cols = columns || (data.length > 0 ? _keys(data[0]).map(function (key) {
|
|
13256
13602
|
return {
|
|
13257
13603
|
key: key,
|
|
13258
13604
|
label: key
|
|
@@ -13271,7 +13617,7 @@
|
|
|
13271
13617
|
var bVal = b[currentSortColumn];
|
|
13272
13618
|
|
|
13273
13619
|
// Handle different types
|
|
13274
|
-
if (
|
|
13620
|
+
if (_is(aVal, 'number') && _is(bVal, 'number')) {
|
|
13275
13621
|
return currentSortDirection === 'asc' ? aVal - bVal : bVal - aVal;
|
|
13276
13622
|
}
|
|
13277
13623
|
|
|
@@ -13286,6 +13632,15 @@
|
|
|
13286
13632
|
});
|
|
13287
13633
|
}
|
|
13288
13634
|
|
|
13635
|
+
// Pagination
|
|
13636
|
+
var totalRows = sortedData.length;
|
|
13637
|
+
var totalPages = pageSize ? Math.max(1, Math.ceil(totalRows / pageSize)) : 1;
|
|
13638
|
+
var page = Math.max(1, Math.min(currentPage, totalPages));
|
|
13639
|
+
if (pageSize) {
|
|
13640
|
+
var start = (page - 1) * pageSize;
|
|
13641
|
+
sortedData = sortedData.slice(start, start + pageSize);
|
|
13642
|
+
}
|
|
13643
|
+
|
|
13289
13644
|
// Create sort handler
|
|
13290
13645
|
var handleSort = function handleSort(column) {
|
|
13291
13646
|
if (!sortable) return;
|
|
@@ -13331,12 +13686,28 @@
|
|
|
13331
13686
|
}
|
|
13332
13687
|
};
|
|
13333
13688
|
|
|
13334
|
-
// Build table body
|
|
13689
|
+
// Build table body with selectable/onRowClick support
|
|
13335
13690
|
var tbody = {
|
|
13336
13691
|
t: 'tbody',
|
|
13337
|
-
c: sortedData.map(function (row) {
|
|
13692
|
+
c: sortedData.map(function (row, idx) {
|
|
13693
|
+
var globalIdx = pageSize ? (page - 1) * pageSize + idx : idx;
|
|
13694
|
+
var rowAttrs = {};
|
|
13695
|
+
if (selectable || onRowClick) {
|
|
13696
|
+
rowAttrs.style = 'cursor:pointer;';
|
|
13697
|
+
rowAttrs.onclick = function (e) {
|
|
13698
|
+
if (selectable) {
|
|
13699
|
+
// Toggle selected class on this row
|
|
13700
|
+
var tr = e.currentTarget;
|
|
13701
|
+
tr.classList.toggle('bw_table_row_selected');
|
|
13702
|
+
}
|
|
13703
|
+
if (onRowClick) {
|
|
13704
|
+
onRowClick(row, globalIdx, e);
|
|
13705
|
+
}
|
|
13706
|
+
};
|
|
13707
|
+
}
|
|
13338
13708
|
return {
|
|
13339
13709
|
t: 'tr',
|
|
13710
|
+
a: rowAttrs,
|
|
13340
13711
|
c: cols.map(function (col) {
|
|
13341
13712
|
return {
|
|
13342
13713
|
t: 'td',
|
|
@@ -13346,13 +13717,65 @@
|
|
|
13346
13717
|
};
|
|
13347
13718
|
})
|
|
13348
13719
|
};
|
|
13349
|
-
|
|
13720
|
+
var table = {
|
|
13350
13721
|
t: 'table',
|
|
13351
13722
|
a: {
|
|
13352
13723
|
"class": cls
|
|
13353
13724
|
},
|
|
13354
13725
|
c: [thead, tbody]
|
|
13355
13726
|
};
|
|
13727
|
+
|
|
13728
|
+
// If no pagination, return table directly
|
|
13729
|
+
if (!pageSize) return table;
|
|
13730
|
+
|
|
13731
|
+
// Build pagination controls
|
|
13732
|
+
var pageButtons = [];
|
|
13733
|
+
// Previous button
|
|
13734
|
+
pageButtons.push({
|
|
13735
|
+
t: 'button',
|
|
13736
|
+
a: {
|
|
13737
|
+
"class": 'bw_btn bw_btn_sm',
|
|
13738
|
+
disabled: page <= 1 ? 'disabled' : undefined,
|
|
13739
|
+
onclick: page > 1 && onPageChange ? function () {
|
|
13740
|
+
onPageChange(page - 1);
|
|
13741
|
+
} : undefined
|
|
13742
|
+
},
|
|
13743
|
+
c: 'Prev'
|
|
13744
|
+
});
|
|
13745
|
+
// Page info
|
|
13746
|
+
pageButtons.push({
|
|
13747
|
+
t: 'span',
|
|
13748
|
+
a: {
|
|
13749
|
+
style: 'margin:0 0.5rem;font-size:0.875rem;'
|
|
13750
|
+
},
|
|
13751
|
+
c: 'Page ' + page + ' of ' + totalPages
|
|
13752
|
+
});
|
|
13753
|
+
// Next button
|
|
13754
|
+
pageButtons.push({
|
|
13755
|
+
t: 'button',
|
|
13756
|
+
a: {
|
|
13757
|
+
"class": 'bw_btn bw_btn_sm',
|
|
13758
|
+
disabled: page >= totalPages ? 'disabled' : undefined,
|
|
13759
|
+
onclick: page < totalPages && onPageChange ? function () {
|
|
13760
|
+
onPageChange(page + 1);
|
|
13761
|
+
} : undefined
|
|
13762
|
+
},
|
|
13763
|
+
c: 'Next'
|
|
13764
|
+
});
|
|
13765
|
+
return {
|
|
13766
|
+
t: 'div',
|
|
13767
|
+
a: {
|
|
13768
|
+
"class": 'bw_table_paginated'
|
|
13769
|
+
},
|
|
13770
|
+
c: [table, {
|
|
13771
|
+
t: 'div',
|
|
13772
|
+
a: {
|
|
13773
|
+
"class": 'bw_table_pagination',
|
|
13774
|
+
style: 'display:flex;align-items:center;justify-content:flex-end;padding:0.5rem 0;gap:0.25rem;'
|
|
13775
|
+
},
|
|
13776
|
+
c: pageButtons
|
|
13777
|
+
}]
|
|
13778
|
+
};
|
|
13356
13779
|
};
|
|
13357
13780
|
|
|
13358
13781
|
/**
|
|
@@ -13395,7 +13818,7 @@
|
|
|
13395
13818
|
headerRow = _config$headerRow === void 0 ? true : _config$headerRow,
|
|
13396
13819
|
columns = config.columns,
|
|
13397
13820
|
rest = _objectWithoutProperties(config, _excluded);
|
|
13398
|
-
if (!
|
|
13821
|
+
if (!_isA(data) || data.length === 0) {
|
|
13399
13822
|
return bw.makeTable(_objectSpread2({
|
|
13400
13823
|
data: [],
|
|
13401
13824
|
columns: columns || []
|
|
@@ -13492,7 +13915,7 @@
|
|
|
13492
13915
|
showLabels = _config$showLabels === void 0 ? true : _config$showLabels,
|
|
13493
13916
|
_config$className2 = config.className,
|
|
13494
13917
|
className = _config$className2 === void 0 ? '' : _config$className2;
|
|
13495
|
-
if (!
|
|
13918
|
+
if (!_isA(data) || data.length === 0) {
|
|
13496
13919
|
return {
|
|
13497
13920
|
t: 'div',
|
|
13498
13921
|
a: {
|
|
@@ -13675,7 +14098,7 @@
|
|
|
13675
14098
|
bw.render = function (element, position, taco) {
|
|
13676
14099
|
var _taco$o4, _taco$o5, _taco$o6;
|
|
13677
14100
|
// Get target element
|
|
13678
|
-
var targetEl =
|
|
14101
|
+
var targetEl = _is(element, 'string') ? document.querySelector(element) : element;
|
|
13679
14102
|
if (!targetEl) {
|
|
13680
14103
|
return {
|
|
13681
14104
|
object_type: 'error',
|
|
@@ -13813,7 +14236,7 @@
|
|
|
13813
14236
|
setContent: function setContent(content) {
|
|
13814
14237
|
this._taco.c = content;
|
|
13815
14238
|
if (this.element) {
|
|
13816
|
-
if (
|
|
14239
|
+
if (_is(content, 'string')) {
|
|
13817
14240
|
this.element.textContent = content;
|
|
13818
14241
|
} else {
|
|
13819
14242
|
// Re-render for complex content
|