bitwrench 2.0.12 → 2.0.14
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 +4 -4
- package/dist/bitwrench-code-edit.cjs.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 +659 -346
- package/dist/bitwrench-lean.cjs.min.js +5 -5
- package/dist/bitwrench-lean.es5.js +960 -347
- package/dist/bitwrench-lean.es5.min.js +3 -3
- package/dist/bitwrench-lean.esm.js +659 -346
- package/dist/bitwrench-lean.esm.min.js +5 -5
- package/dist/bitwrench-lean.umd.js +659 -346
- package/dist/bitwrench-lean.umd.min.js +5 -5
- package/dist/bitwrench.cjs.js +1737 -452
- package/dist/bitwrench.cjs.min.js +6 -6
- package/dist/bitwrench.css +1625 -168
- package/dist/bitwrench.es5.js +4016 -2341
- package/dist/bitwrench.es5.min.js +4 -4
- package/dist/bitwrench.esm.js +1737 -452
- package/dist/bitwrench.esm.min.js +6 -6
- package/dist/bitwrench.umd.js +1737 -452
- package/dist/bitwrench.umd.min.js +6 -6
- package/dist/builds.json +61 -61
- package/dist/sri.json +26 -26
- package/package.json +1 -1
- package/readme.html +5 -5
- package/src/bitwrench-color-utils.js +137 -17
- package/src/bitwrench-components-v2.js +997 -35
- package/src/bitwrench-styles.js +1098 -370
- package/src/bitwrench.js +128 -75
- package/src/version.js +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! bitwrench-lean v2.0.
|
|
1
|
+
/*! bitwrench-lean v2.0.14 | 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) :
|
|
@@ -189,14 +189,14 @@
|
|
|
189
189
|
*/
|
|
190
190
|
|
|
191
191
|
var VERSION_INFO = {
|
|
192
|
-
version: '2.0.
|
|
192
|
+
version: '2.0.14',
|
|
193
193
|
name: 'bitwrench',
|
|
194
194
|
description: 'A library for javascript UI functions.',
|
|
195
195
|
license: 'BSD-2-Clause',
|
|
196
196
|
homepage: 'https://deftio.github.com/bitwrench/pages',
|
|
197
197
|
repository: 'git+https://github.com/deftio/bitwrench.git',
|
|
198
198
|
author: 'manu a. chatterjee <deftio@deftio.com> (https://deftio.com/)',
|
|
199
|
-
buildDate: '2026-03-
|
|
199
|
+
buildDate: '2026-03-08T08:04:06.572Z'
|
|
200
200
|
};
|
|
201
201
|
|
|
202
202
|
/**
|
|
@@ -445,6 +445,28 @@
|
|
|
445
445
|
return relativeLuminance(hex) > 0.179 ? '#000' : '#fff';
|
|
446
446
|
}
|
|
447
447
|
|
|
448
|
+
/**
|
|
449
|
+
* Shift a color's hue toward a target hue by a given amount.
|
|
450
|
+
* Uses shortest-arc interpolation on the hue wheel.
|
|
451
|
+
* @param {string} sourceHex - Color to shift
|
|
452
|
+
* @param {string} targetHex - Color whose hue to shift toward
|
|
453
|
+
* @param {number} [amount=0.20] - 0 = no shift, 1 = full shift to target hue
|
|
454
|
+
* @returns {string} Harmonized hex color
|
|
455
|
+
*/
|
|
456
|
+
function harmonize(sourceHex, targetHex, amount) {
|
|
457
|
+
if (amount === undefined) amount = 0.20;
|
|
458
|
+
if (amount === 0) return sourceHex;
|
|
459
|
+
var srcHsl = hexToHsl(sourceHex);
|
|
460
|
+
var tgtHsl = hexToHsl(targetHex);
|
|
461
|
+
|
|
462
|
+
// Shortest-arc hue interpolation
|
|
463
|
+
var diff = tgtHsl[0] - srcHsl[0];
|
|
464
|
+
if (diff > 180) diff -= 360;
|
|
465
|
+
if (diff < -180) diff += 360;
|
|
466
|
+
var newHue = (srcHsl[0] + diff * amount + 360) % 360;
|
|
467
|
+
return hslToHex([newHue, srcHsl[1], srcHsl[2]]);
|
|
468
|
+
}
|
|
469
|
+
|
|
448
470
|
/**
|
|
449
471
|
* Derive a full shade palette for a single semantic color.
|
|
450
472
|
* @param {string} hex - Base color hex
|
|
@@ -465,29 +487,126 @@
|
|
|
465
487
|
}
|
|
466
488
|
|
|
467
489
|
/**
|
|
468
|
-
* Derive
|
|
469
|
-
*
|
|
470
|
-
* @
|
|
490
|
+
* Derive the alternate (luminance-inverted) version of a single seed color.
|
|
491
|
+
* Preserves hue, mirrors lightness, adjusts saturation for readability.
|
|
492
|
+
* @param {string} hex - Seed hex color
|
|
493
|
+
* @returns {string} Alternate hex color
|
|
471
494
|
*/
|
|
472
|
-
function
|
|
473
|
-
var
|
|
495
|
+
function deriveAlternateSeed(hex) {
|
|
496
|
+
var hsl = hexToHsl(hex);
|
|
497
|
+
var h = hsl[0],
|
|
498
|
+
s = hsl[1],
|
|
499
|
+
l = hsl[2];
|
|
500
|
+
var altL, altS;
|
|
501
|
+
if (l > 50) {
|
|
502
|
+
// Light color → make dark. Map 50-100 → 30-10 range
|
|
503
|
+
altL = clip(100 - l - 10, 8, 40);
|
|
504
|
+
// Reduce saturation slightly — vivid colors at low lightness look garish
|
|
505
|
+
altS = clip(s * 0.85, 0, 100);
|
|
506
|
+
} else {
|
|
507
|
+
// Dark color → make light. Map 0-50 → 65-92 range
|
|
508
|
+
altL = clip(100 - l + 10, 60, 92);
|
|
509
|
+
// Slightly increase saturation for light variant
|
|
510
|
+
altS = clip(s * 1.1, 0, 100);
|
|
511
|
+
}
|
|
512
|
+
return hslToHex([h, altS, altL]);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Determine whether a palette config is "light-flavored" based on
|
|
517
|
+
* the average luminance of its seed colors.
|
|
518
|
+
* @param {Object} config - Theme config with primary, secondary hex colors
|
|
519
|
+
* @returns {boolean} true if the seeds are predominantly light
|
|
520
|
+
*/
|
|
521
|
+
function isLightPalette(config) {
|
|
522
|
+
var lum = relativeLuminance(config.primary);
|
|
523
|
+
if (config.secondary) lum = (lum + relativeLuminance(config.secondary)) / 2;
|
|
524
|
+
if (config.tertiary) lum = (lum * 2 + relativeLuminance(config.tertiary)) / 3;
|
|
525
|
+
return lum > 0.179;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Derive a complete alternate config from a primary theme config.
|
|
530
|
+
* Each seed color is luminance-inverted; semantic colors are adjusted for
|
|
531
|
+
* the new luminance context.
|
|
532
|
+
* @param {Object} config - Primary theme config
|
|
533
|
+
* @returns {Object} Alternate theme config (same shape, inverted lightness)
|
|
534
|
+
*/
|
|
535
|
+
function deriveAlternateConfig(config) {
|
|
536
|
+
var alt = {};
|
|
537
|
+
// Invert the user's seed colors
|
|
538
|
+
alt.primary = deriveAlternateSeed(config.primary);
|
|
539
|
+
alt.secondary = deriveAlternateSeed(config.secondary);
|
|
540
|
+
alt.tertiary = config.tertiary ? deriveAlternateSeed(config.tertiary) : alt.primary;
|
|
541
|
+
|
|
542
|
+
// Derive alternate surface colors from primary hue
|
|
543
|
+
var priHsl = hexToHsl(config.primary);
|
|
544
|
+
var h = priHsl[0];
|
|
545
|
+
var isLight = isLightPalette(config);
|
|
546
|
+
if (isLight) {
|
|
547
|
+
// Primary is light → alternate needs dark surfaces
|
|
548
|
+
alt.light = hslToHex([h, Math.min(priHsl[1], 15), 15]);
|
|
549
|
+
alt.dark = hslToHex([h, 5, 88]);
|
|
550
|
+
} else {
|
|
551
|
+
// Primary is dark → alternate needs light surfaces
|
|
552
|
+
alt.light = hslToHex([h, Math.min(priHsl[1], 10), 96]);
|
|
553
|
+
alt.dark = hslToHex([h, 10, 18]);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Semantic colors: harmonize toward primary, then invert for alternate
|
|
557
|
+
var amt = config.harmonize !== undefined ? config.harmonize : 0.20;
|
|
558
|
+
var semanticDefaults = {
|
|
474
559
|
success: '#198754',
|
|
475
560
|
danger: '#dc3545',
|
|
476
|
-
warning: '#
|
|
477
|
-
info: '#
|
|
478
|
-
light: '#f8f9fa',
|
|
479
|
-
dark: '#212529'
|
|
561
|
+
warning: '#f0ad4e',
|
|
562
|
+
info: '#17a2b8'
|
|
480
563
|
};
|
|
564
|
+
var semantics = ['success', 'danger', 'warning', 'info'];
|
|
565
|
+
for (var i = 0; i < semantics.length; i++) {
|
|
566
|
+
var key = semantics[i];
|
|
567
|
+
var seed = config[key] || semanticDefaults[key];
|
|
568
|
+
var harmonized = harmonize(seed, config.primary, amt);
|
|
569
|
+
alt[key] = deriveAlternateSeed(harmonized);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// Semantic colors are already harmonized+inverted — don't re-harmonize in derivePalette
|
|
573
|
+
alt.harmonize = 0;
|
|
574
|
+
return alt;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Derive complete palette from a theme config object.
|
|
579
|
+
* Semantic colors are harmonized toward the primary hue (configurable).
|
|
580
|
+
* Light/dark surface colors are tinted with the primary hue.
|
|
581
|
+
* @param {Object} config - Theme config with primary, secondary, tertiary, etc.
|
|
582
|
+
* @param {number} [config.harmonize=0.20] - Hue shift amount for semantic colors (0-1)
|
|
583
|
+
* @returns {Object} Full palette with shades for all 9 semantic colors
|
|
584
|
+
*/
|
|
585
|
+
function derivePalette(config) {
|
|
586
|
+
var amt = config.harmonize !== undefined ? config.harmonize : 0.20;
|
|
587
|
+
var pri = config.primary;
|
|
588
|
+
var priHsl = hexToHsl(pri);
|
|
589
|
+
var h = priHsl[0];
|
|
590
|
+
|
|
591
|
+
// Semantic defaults — harmonized toward primary hue
|
|
592
|
+
var successBase = harmonize(config.success || '#198754', pri, amt);
|
|
593
|
+
var dangerBase = harmonize(config.danger || '#dc3545', pri, amt);
|
|
594
|
+
var warningBase = harmonize(config.warning || '#f0ad4e', pri, amt);
|
|
595
|
+
var infoBase = harmonize(config.info || '#17a2b8', pri, amt);
|
|
596
|
+
|
|
597
|
+
// Light/dark: derive from primary hue with low saturation (if not user-supplied)
|
|
598
|
+
var lightBase = config.light || hslToHex([h, 8, 97]);
|
|
599
|
+
var darkBase = config.dark || hslToHex([h, 10, 13]);
|
|
481
600
|
var palette = {
|
|
482
601
|
primary: deriveShades(config.primary),
|
|
483
602
|
secondary: deriveShades(config.secondary),
|
|
484
603
|
tertiary: deriveShades(config.tertiary),
|
|
485
|
-
success: deriveShades(
|
|
486
|
-
danger: deriveShades(
|
|
487
|
-
warning: deriveShades(
|
|
488
|
-
info: deriveShades(
|
|
489
|
-
light: deriveShades(
|
|
490
|
-
dark: deriveShades(
|
|
604
|
+
success: deriveShades(successBase),
|
|
605
|
+
danger: deriveShades(dangerBase),
|
|
606
|
+
warning: deriveShades(warningBase),
|
|
607
|
+
info: deriveShades(infoBase),
|
|
608
|
+
light: deriveShades(lightBase),
|
|
609
|
+
dark: deriveShades(darkBase)
|
|
491
610
|
};
|
|
492
611
|
return palette;
|
|
493
612
|
}
|
|
@@ -559,6 +678,88 @@
|
|
|
559
678
|
}
|
|
560
679
|
};
|
|
561
680
|
|
|
681
|
+
// ---- Typography scale presets ----
|
|
682
|
+
|
|
683
|
+
var TYPE_RATIO_PRESETS = {
|
|
684
|
+
tight: 1.125,
|
|
685
|
+
normal: 1.200,
|
|
686
|
+
relaxed: 1.250,
|
|
687
|
+
dramatic: 1.333
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Generate a modular type scale from a base size and ratio.
|
|
692
|
+
* @param {number} base - Base font size in px (default 16)
|
|
693
|
+
* @param {number} ratio - Scale ratio (default 1.200)
|
|
694
|
+
* @returns {Object} { xs, sm, base, lg, xl, '2xl', '3xl', '4xl' } in px
|
|
695
|
+
*/
|
|
696
|
+
function generateTypeScale(base, ratio) {
|
|
697
|
+
if (!base) base = 16;
|
|
698
|
+
if (!ratio) ratio = 1.200;
|
|
699
|
+
return {
|
|
700
|
+
xs: Math.round(base / (ratio * ratio)),
|
|
701
|
+
sm: Math.round(base / ratio),
|
|
702
|
+
base: base,
|
|
703
|
+
lg: Math.round(base * ratio),
|
|
704
|
+
xl: Math.round(base * ratio * ratio),
|
|
705
|
+
'2xl': Math.round(base * Math.pow(ratio, 3)),
|
|
706
|
+
'3xl': Math.round(base * Math.pow(ratio, 4)),
|
|
707
|
+
'4xl': Math.round(base * Math.pow(ratio, 5))
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// ---- Elevation (shadow depth) presets ----
|
|
712
|
+
|
|
713
|
+
var ELEVATION_PRESETS = {
|
|
714
|
+
flat: {
|
|
715
|
+
sm: 'none',
|
|
716
|
+
md: 'none',
|
|
717
|
+
lg: 'none',
|
|
718
|
+
xl: 'none'
|
|
719
|
+
},
|
|
720
|
+
sm: {
|
|
721
|
+
sm: '0 1px 2px rgba(0,0,0,0.05)',
|
|
722
|
+
md: '0 1px 3px rgba(0,0,0,0.08)',
|
|
723
|
+
lg: '0 2px 6px rgba(0,0,0,0.10)',
|
|
724
|
+
xl: '0 4px 12px rgba(0,0,0,0.12)'
|
|
725
|
+
},
|
|
726
|
+
md: {
|
|
727
|
+
sm: '0 1px 3px rgba(0,0,0,0.08)',
|
|
728
|
+
md: '0 2px 6px rgba(0,0,0,0.12)',
|
|
729
|
+
lg: '0 4px 12px rgba(0,0,0,0.16)',
|
|
730
|
+
xl: '0 8px 24px rgba(0,0,0,0.20)'
|
|
731
|
+
},
|
|
732
|
+
lg: {
|
|
733
|
+
sm: '0 2px 4px rgba(0,0,0,0.10)',
|
|
734
|
+
md: '0 4px 12px rgba(0,0,0,0.16)',
|
|
735
|
+
lg: '0 8px 24px rgba(0,0,0,0.22)',
|
|
736
|
+
xl: '0 16px 48px rgba(0,0,0,0.28)'
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
// ---- Motion (transition) presets ----
|
|
741
|
+
|
|
742
|
+
var MOTION_PRESETS = {
|
|
743
|
+
reduced: {
|
|
744
|
+
fast: '0ms',
|
|
745
|
+
normal: '0ms',
|
|
746
|
+
slow: '0ms',
|
|
747
|
+
easing: 'linear'
|
|
748
|
+
},
|
|
749
|
+
standard: {
|
|
750
|
+
fast: '100ms',
|
|
751
|
+
normal: '200ms',
|
|
752
|
+
slow: '300ms',
|
|
753
|
+
easing: 'ease-out'
|
|
754
|
+
},
|
|
755
|
+
expressive: {
|
|
756
|
+
fast: '150ms',
|
|
757
|
+
normal: '300ms',
|
|
758
|
+
slow: '500ms',
|
|
759
|
+
easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
|
|
562
763
|
/**
|
|
563
764
|
* Default palette config — matches existing hardcoded colors
|
|
564
765
|
*/
|
|
@@ -568,8 +769,8 @@
|
|
|
568
769
|
tertiary: '#006666',
|
|
569
770
|
success: '#198754',
|
|
570
771
|
danger: '#dc3545',
|
|
571
|
-
warning: '#
|
|
572
|
-
info: '#
|
|
772
|
+
warning: '#b38600',
|
|
773
|
+
info: '#0891b2',
|
|
573
774
|
light: '#f8f9fa',
|
|
574
775
|
dark: '#212529'
|
|
575
776
|
};
|
|
@@ -666,18 +867,31 @@
|
|
|
666
867
|
};
|
|
667
868
|
|
|
668
869
|
/**
|
|
669
|
-
* Resolve layout config to spacing
|
|
670
|
-
* @param {Object} config - { spacing, radius, fontSize }
|
|
671
|
-
* @returns {Object} { spacing, radius, fontSize }
|
|
870
|
+
* Resolve layout config to spacing, radius, typeScale, elevation, and motion objects.
|
|
871
|
+
* @param {Object} config - { spacing, radius, fontSize, typeRatio, elevation, motion }
|
|
872
|
+
* @returns {Object} { spacing, radius, fontSize, typeScale, elevation, motion }
|
|
672
873
|
*/
|
|
673
874
|
function resolveLayout(config) {
|
|
674
875
|
var sp = config && config.spacing || 'normal';
|
|
675
876
|
var rd = config && config.radius || 'md';
|
|
676
877
|
var fs = config && config.fontSize || 1.0;
|
|
878
|
+
|
|
879
|
+
// typeRatio: accept preset name or number
|
|
880
|
+
var tr = config && config.typeRatio || 'normal';
|
|
881
|
+
var ratioNum = typeof tr === 'string' ? TYPE_RATIO_PRESETS[tr] || TYPE_RATIO_PRESETS.normal : tr;
|
|
882
|
+
|
|
883
|
+
// elevation: accept preset name or object
|
|
884
|
+
var el = config && config.elevation || 'md';
|
|
885
|
+
|
|
886
|
+
// motion: accept preset name or object
|
|
887
|
+
var mo = config && config.motion || 'standard';
|
|
677
888
|
return {
|
|
678
889
|
spacing: typeof sp === 'string' ? SPACING_PRESETS[sp] || SPACING_PRESETS.normal : sp,
|
|
679
890
|
radius: typeof rd === 'string' ? RADIUS_PRESETS[rd] || RADIUS_PRESETS.md : rd,
|
|
680
|
-
fontSize: fs
|
|
891
|
+
fontSize: fs,
|
|
892
|
+
typeScale: generateTypeScale(16, ratioNum),
|
|
893
|
+
elevation: typeof el === 'string' ? ELEVATION_PRESETS[el] || ELEVATION_PRESETS.md : el,
|
|
894
|
+
motion: typeof mo === 'string' ? MOTION_PRESETS[mo] || MOTION_PRESETS.standard : mo
|
|
681
895
|
};
|
|
682
896
|
}
|
|
683
897
|
|
|
@@ -703,12 +917,13 @@
|
|
|
703
917
|
// Themed CSS generators
|
|
704
918
|
// =========================================================================
|
|
705
919
|
|
|
706
|
-
function generateTypographyThemed(scope, palette) {
|
|
920
|
+
function generateTypographyThemed(scope, palette, layout) {
|
|
921
|
+
var mot = layout.motion;
|
|
707
922
|
var rules = {};
|
|
708
923
|
rules[scopeSelector(scope, 'a')] = {
|
|
709
924
|
'color': palette.primary.base,
|
|
710
925
|
'text-decoration': 'none',
|
|
711
|
-
'transition': 'color
|
|
926
|
+
'transition': 'color ' + mot.fast + ' ' + mot.easing
|
|
712
927
|
};
|
|
713
928
|
rules[scopeSelector(scope, 'a:hover')] = {
|
|
714
929
|
'color': palette.primary.hover,
|
|
@@ -727,7 +942,8 @@
|
|
|
727
942
|
'border-radius': rd.btn
|
|
728
943
|
};
|
|
729
944
|
rules[scopeSelector(scope, '.bw-btn:focus-visible')] = {
|
|
730
|
-
'outline': '
|
|
945
|
+
'outline': '2px solid currentColor',
|
|
946
|
+
'outline-offset': '2px',
|
|
731
947
|
'box-shadow': '0 0 0 3px ' + palette.primary.focus
|
|
732
948
|
};
|
|
733
949
|
|
|
@@ -809,14 +1025,15 @@
|
|
|
809
1025
|
var rules = {};
|
|
810
1026
|
var sp = layout.spacing;
|
|
811
1027
|
var rd = layout.radius;
|
|
1028
|
+
var elev = layout.elevation;
|
|
812
1029
|
rules[scopeSelector(scope, '.bw-card')] = {
|
|
813
1030
|
'background-color': '#fff',
|
|
814
1031
|
'border': '1px solid ' + palette.light.border,
|
|
815
1032
|
'border-radius': rd.card,
|
|
816
|
-
'box-shadow':
|
|
1033
|
+
'box-shadow': elev.sm
|
|
817
1034
|
};
|
|
818
1035
|
rules[scopeSelector(scope, '.bw-card:hover')] = {
|
|
819
|
-
'box-shadow':
|
|
1036
|
+
'box-shadow': elev.md
|
|
820
1037
|
};
|
|
821
1038
|
rules[scopeSelector(scope, '.bw-card-body')] = {
|
|
822
1039
|
'padding': sp.card
|
|
@@ -862,6 +1079,8 @@
|
|
|
862
1079
|
};
|
|
863
1080
|
rules[scopeSelector(scope, '.bw-form-control:focus')] = {
|
|
864
1081
|
'border-color': palette.primary.border,
|
|
1082
|
+
'outline': '2px solid ' + palette.primary.base,
|
|
1083
|
+
'outline-offset': '-1px',
|
|
865
1084
|
'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
|
|
866
1085
|
};
|
|
867
1086
|
rules[scopeSelector(scope, '.bw-form-control::placeholder')] = {
|
|
@@ -1009,7 +1228,8 @@
|
|
|
1009
1228
|
'border-color': palette.light.border
|
|
1010
1229
|
};
|
|
1011
1230
|
rules[scopeSelector(scope, '.bw-page-link:focus')] = {
|
|
1012
|
-
'
|
|
1231
|
+
'outline': '2px solid ' + palette.primary.base,
|
|
1232
|
+
'outline-offset': '-2px'
|
|
1013
1233
|
};
|
|
1014
1234
|
rules[scopeSelector(scope, '.bw-page-item.bw-active .bw-page-link')] = {
|
|
1015
1235
|
'color': palette.primary.textOn,
|
|
@@ -1165,12 +1385,12 @@
|
|
|
1165
1385
|
};
|
|
1166
1386
|
return rules;
|
|
1167
1387
|
}
|
|
1168
|
-
function generateModalThemed(scope, palette) {
|
|
1388
|
+
function generateModalThemed(scope, palette, layout) {
|
|
1169
1389
|
var rules = {};
|
|
1170
1390
|
rules[scopeSelector(scope, '.bw-modal-content')] = {
|
|
1171
1391
|
'background-color': '#fff',
|
|
1172
1392
|
'border-color': palette.light.border,
|
|
1173
|
-
'box-shadow':
|
|
1393
|
+
'box-shadow': layout.elevation.lg
|
|
1174
1394
|
};
|
|
1175
1395
|
rules[scopeSelector(scope, '.bw-modal-header')] = {
|
|
1176
1396
|
'border-bottom-color': palette.light.border
|
|
@@ -1183,12 +1403,12 @@
|
|
|
1183
1403
|
};
|
|
1184
1404
|
return rules;
|
|
1185
1405
|
}
|
|
1186
|
-
function generateToastThemed(scope, palette) {
|
|
1406
|
+
function generateToastThemed(scope, palette, layout) {
|
|
1187
1407
|
var rules = {};
|
|
1188
1408
|
rules[scopeSelector(scope, '.bw-toast')] = {
|
|
1189
1409
|
'background-color': '#fff',
|
|
1190
1410
|
'border-color': 'rgba(0,0,0,0.1)',
|
|
1191
|
-
'box-shadow':
|
|
1411
|
+
'box-shadow': layout.elevation.lg
|
|
1192
1412
|
};
|
|
1193
1413
|
rules[scopeSelector(scope, '.bw-toast-header')] = {
|
|
1194
1414
|
'border-bottom-color': 'rgba(0,0,0,0.05)'
|
|
@@ -1201,12 +1421,12 @@
|
|
|
1201
1421
|
});
|
|
1202
1422
|
return rules;
|
|
1203
1423
|
}
|
|
1204
|
-
function generateDropdownThemed(scope, palette) {
|
|
1424
|
+
function generateDropdownThemed(scope, palette, layout) {
|
|
1205
1425
|
var rules = {};
|
|
1206
1426
|
rules[scopeSelector(scope, '.bw-dropdown-menu')] = {
|
|
1207
1427
|
'background-color': '#fff',
|
|
1208
1428
|
'border-color': palette.light.border,
|
|
1209
|
-
'box-shadow':
|
|
1429
|
+
'box-shadow': layout.elevation.md
|
|
1210
1430
|
};
|
|
1211
1431
|
rules[scopeSelector(scope, '.bw-dropdown-item')] = {
|
|
1212
1432
|
'color': palette.dark.base
|
|
@@ -1267,7 +1487,7 @@
|
|
|
1267
1487
|
* @returns {Object} CSS rules object
|
|
1268
1488
|
*/
|
|
1269
1489
|
function generateThemedCSS(scopeName, palette, layout) {
|
|
1270
|
-
return Object.assign({}, generateResetThemed(scopeName, palette), generateTypographyThemed(scopeName, palette), generateButtons(scopeName, palette, layout), generateAlerts(scopeName, palette, layout), generateBadges(scopeName, palette), 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), generateHero(scopeName, palette), generateBreadcrumbThemed(scopeName, palette), generateSpinnerThemed(scopeName, palette), generateCloseButtonThemed(scopeName, palette), generateSectionsThemed(scopeName, palette), generateAccordionThemed(scopeName, palette), generateCarouselThemed(scopeName, palette), generateModalThemed(scopeName, palette), generateToastThemed(scopeName, palette), generateDropdownThemed(scopeName, palette), generateSwitchThemed(scopeName, palette), generateSkeletonThemed(scopeName, palette), generateAvatarThemed(scopeName, palette), generateUtilityColors(scopeName, palette));
|
|
1490
|
+
return Object.assign({}, generateResetThemed(scopeName, palette), generateTypographyThemed(scopeName, palette, layout), generateButtons(scopeName, palette, layout), generateAlerts(scopeName, palette, layout), generateBadges(scopeName, palette), 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), generateHero(scopeName, palette), generateBreadcrumbThemed(scopeName, palette), generateSpinnerThemed(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), generateAvatarThemed(scopeName, palette), generateUtilityColors(scopeName, palette));
|
|
1271
1491
|
}
|
|
1272
1492
|
|
|
1273
1493
|
// =========================================================================
|
|
@@ -1617,11 +1837,23 @@
|
|
|
1617
1837
|
// =========================================================================
|
|
1618
1838
|
|
|
1619
1839
|
/**
|
|
1620
|
-
* Structural styles
|
|
1621
|
-
* properties. No colors, backgrounds, shadows, or border-colors.
|
|
1622
|
-
* These never change with themes.
|
|
1840
|
+
* Structural styles — layout, sizing, spacing, positioning, and behavior.
|
|
1623
1841
|
*
|
|
1624
|
-
*
|
|
1842
|
+
* POLICY: No colors, backgrounds, shadows, or border-colors in this function.
|
|
1843
|
+
* All cosmetic values belong in `defaultStyles.*` sections (unthemed defaults)
|
|
1844
|
+
* or in `generateThemedCSS()` (theme-driven colors).
|
|
1845
|
+
*
|
|
1846
|
+
* Exception: `.bw-progress-bar-striped` uses rgba(255,255,255,.15) for the
|
|
1847
|
+
* stripe pattern overlay. This is theme-neutral — a semi-transparent white
|
|
1848
|
+
* gradient that creates visible stripes on any background color.
|
|
1849
|
+
*
|
|
1850
|
+
* Architecture:
|
|
1851
|
+
* getStructuralStyles() → layout-only rules (never change with themes)
|
|
1852
|
+
* defaultStyles.* → cosmetic defaults (colors, shadows, borders)
|
|
1853
|
+
* generateThemedCSS() → palette-driven cosmetics from seed colors
|
|
1854
|
+
* generateAlternateCSS() → alternate palette (luminance-inverted)
|
|
1855
|
+
*
|
|
1856
|
+
* @returns {Object} CSS rules object (layout-only, theme-independent)
|
|
1625
1857
|
*/
|
|
1626
1858
|
function getStructuralStyles() {
|
|
1627
1859
|
var rules = {};
|
|
@@ -1730,7 +1962,7 @@
|
|
|
1730
1962
|
'font-size': '0.875rem',
|
|
1731
1963
|
'font-family': 'inherit',
|
|
1732
1964
|
'border-radius': '6px',
|
|
1733
|
-
'transition': 'all 0.15s
|
|
1965
|
+
'transition': 'all 0.15s ease-out',
|
|
1734
1966
|
'gap': '0.5rem'
|
|
1735
1967
|
};
|
|
1736
1968
|
rules['.bw-btn:hover'] = {
|
|
@@ -1741,7 +1973,8 @@
|
|
|
1741
1973
|
'transform': 'translateY(0)'
|
|
1742
1974
|
};
|
|
1743
1975
|
rules['.bw-btn:focus-visible'] = {
|
|
1744
|
-
'outline': '
|
|
1976
|
+
'outline': '2px solid currentColor',
|
|
1977
|
+
'outline-offset': '2px'
|
|
1745
1978
|
};
|
|
1746
1979
|
rules['.bw-btn:disabled'] = {
|
|
1747
1980
|
'opacity': '0.5',
|
|
@@ -1770,7 +2003,7 @@
|
|
|
1770
2003
|
'background-clip': 'border-box',
|
|
1771
2004
|
'border': '1px solid transparent',
|
|
1772
2005
|
'border-radius': '8px',
|
|
1773
|
-
'transition': 'box-shadow 0.2s
|
|
2006
|
+
'transition': 'box-shadow 0.2s ease-out, transform 0.2s ease-out',
|
|
1774
2007
|
'margin-bottom': '1.5rem',
|
|
1775
2008
|
'overflow': 'hidden'
|
|
1776
2009
|
};
|
|
@@ -1803,7 +2036,7 @@
|
|
|
1803
2036
|
'font-size': '0.875rem'
|
|
1804
2037
|
};
|
|
1805
2038
|
rules['.bw-card-hoverable'] = {
|
|
1806
|
-
'transition': 'all 0.3s
|
|
2039
|
+
'transition': 'all 0.3s ease-out'
|
|
1807
2040
|
};
|
|
1808
2041
|
rules['.bw-card-img-top'] = {
|
|
1809
2042
|
'width': '100%',
|
|
@@ -1841,11 +2074,12 @@
|
|
|
1841
2074
|
'appearance': 'none',
|
|
1842
2075
|
'border': '1px solid transparent',
|
|
1843
2076
|
'border-radius': '6px',
|
|
1844
|
-
'transition': 'border-color 0.15s ease-
|
|
2077
|
+
'transition': 'border-color 0.15s ease-out, box-shadow 0.15s ease-out',
|
|
1845
2078
|
'font-family': 'inherit'
|
|
1846
2079
|
};
|
|
1847
2080
|
rules['.bw-form-control:focus'] = {
|
|
1848
|
-
'outline': '
|
|
2081
|
+
'outline': '2px solid currentColor',
|
|
2082
|
+
'outline-offset': '-1px'
|
|
1849
2083
|
};
|
|
1850
2084
|
rules['.bw-form-control::placeholder'] = {
|
|
1851
2085
|
'opacity': '1'
|
|
@@ -1874,6 +2108,18 @@
|
|
|
1874
2108
|
'resize': 'vertical'
|
|
1875
2109
|
};
|
|
1876
2110
|
|
|
2111
|
+
// Form validation (structural)
|
|
2112
|
+
rules['.bw-valid-feedback'] = {
|
|
2113
|
+
'display': 'block',
|
|
2114
|
+
'font-size': '0.875rem',
|
|
2115
|
+
'margin-top': '0.25rem'
|
|
2116
|
+
};
|
|
2117
|
+
rules['.bw-invalid-feedback'] = {
|
|
2118
|
+
'display': 'block',
|
|
2119
|
+
'font-size': '0.875rem',
|
|
2120
|
+
'margin-top': '0.25rem'
|
|
2121
|
+
};
|
|
2122
|
+
|
|
1877
2123
|
// Form checks (structural)
|
|
1878
2124
|
Object.assign(rules, {
|
|
1879
2125
|
'.bw-form-check': {
|
|
@@ -2014,8 +2260,8 @@
|
|
|
2014
2260
|
// Badges (structural)
|
|
2015
2261
|
rules['.bw-badge'] = {
|
|
2016
2262
|
'display': 'inline-block',
|
|
2017
|
-
'padding': '.
|
|
2018
|
-
'font-size': '.
|
|
2263
|
+
'padding': '0.375rem 0.625rem',
|
|
2264
|
+
'font-size': '0.875rem',
|
|
2019
2265
|
'font-weight': '600',
|
|
2020
2266
|
'line-height': '1.3',
|
|
2021
2267
|
'text-align': 'center',
|
|
@@ -2027,12 +2273,12 @@
|
|
|
2027
2273
|
'display': 'none'
|
|
2028
2274
|
};
|
|
2029
2275
|
rules['.bw-badge-sm'] = {
|
|
2030
|
-
'font-size': '.
|
|
2031
|
-
'padding': '.
|
|
2276
|
+
'font-size': '0.75rem',
|
|
2277
|
+
'padding': '0.25rem 0.5rem'
|
|
2032
2278
|
};
|
|
2033
2279
|
rules['.bw-badge-lg'] = {
|
|
2034
|
-
'font-size': '
|
|
2035
|
-
'padding': '.
|
|
2280
|
+
'font-size': '1rem',
|
|
2281
|
+
'padding': '0.5rem 0.875rem'
|
|
2036
2282
|
};
|
|
2037
2283
|
rules['.bw-badge-pill'] = {
|
|
2038
2284
|
'border-radius': '50rem'
|
|
@@ -2053,7 +2299,7 @@
|
|
|
2053
2299
|
'overflow': 'hidden',
|
|
2054
2300
|
'text-align': 'center',
|
|
2055
2301
|
'white-space': 'nowrap',
|
|
2056
|
-
'transition': 'width .
|
|
2302
|
+
'transition': 'width 0.3s ease-out',
|
|
2057
2303
|
'font-weight': '600'
|
|
2058
2304
|
};
|
|
2059
2305
|
rules['.bw-progress-bar-striped'] = {
|
|
@@ -2093,7 +2339,7 @@
|
|
|
2093
2339
|
'cursor': 'pointer',
|
|
2094
2340
|
'border': 'none',
|
|
2095
2341
|
'background': 'transparent',
|
|
2096
|
-
'transition': 'color 0.15s, border-color 0.15s',
|
|
2342
|
+
'transition': 'color 0.15s ease-out, background-color 0.15s ease-out, border-color 0.15s ease-out',
|
|
2097
2343
|
'font-family': 'inherit'
|
|
2098
2344
|
};
|
|
2099
2345
|
rules['.bw-nav-tabs .bw-nav-link'] = {
|
|
@@ -2157,7 +2403,13 @@
|
|
|
2157
2403
|
'pointer-events': 'none'
|
|
2158
2404
|
};
|
|
2159
2405
|
rules['a.bw-list-group-item'] = {
|
|
2160
|
-
'cursor': 'pointer'
|
|
2406
|
+
'cursor': 'pointer',
|
|
2407
|
+
'transition': 'background-color 0.15s ease-out, color 0.15s ease-out'
|
|
2408
|
+
};
|
|
2409
|
+
rules['a.bw-list-group-item:focus-visible, .bw-list-group-item:focus-visible'] = {
|
|
2410
|
+
'z-index': '2',
|
|
2411
|
+
'outline': '2px solid currentColor',
|
|
2412
|
+
'outline-offset': '-2px'
|
|
2161
2413
|
};
|
|
2162
2414
|
rules['.bw-list-group-flush'] = {
|
|
2163
2415
|
'border-radius': '0'
|
|
@@ -2188,7 +2440,7 @@
|
|
|
2188
2440
|
'margin-left': '-1px',
|
|
2189
2441
|
'line-height': '1.25',
|
|
2190
2442
|
'text-decoration': 'none',
|
|
2191
|
-
'transition': 'color 0.15s ease-
|
|
2443
|
+
'transition': 'color 0.15s ease-out, background-color 0.15s ease-out, border-color 0.15s ease-out'
|
|
2192
2444
|
};
|
|
2193
2445
|
rules['.bw-page-item:first-child .bw-page-link'] = {
|
|
2194
2446
|
'margin-left': '0',
|
|
@@ -2199,6 +2451,11 @@
|
|
|
2199
2451
|
'border-top-right-radius': '0.375rem',
|
|
2200
2452
|
'border-bottom-right-radius': '0.375rem'
|
|
2201
2453
|
};
|
|
2454
|
+
rules['.bw-page-link:focus-visible'] = {
|
|
2455
|
+
'z-index': '3',
|
|
2456
|
+
'outline': '2px solid currentColor',
|
|
2457
|
+
'outline-offset': '-2px'
|
|
2458
|
+
};
|
|
2202
2459
|
|
|
2203
2460
|
// Breadcrumb (structural)
|
|
2204
2461
|
rules['.bw-breadcrumb'] = {
|
|
@@ -2219,6 +2476,13 @@
|
|
|
2219
2476
|
'padding-right': '0.5rem',
|
|
2220
2477
|
'content': '"/"'
|
|
2221
2478
|
};
|
|
2479
|
+
rules['.bw-breadcrumb-item a'] = {
|
|
2480
|
+
'text-decoration': 'none',
|
|
2481
|
+
'transition': 'color 0.15s ease-out'
|
|
2482
|
+
};
|
|
2483
|
+
rules['.bw-breadcrumb-item.active'] = {
|
|
2484
|
+
'font-weight': '500'
|
|
2485
|
+
};
|
|
2222
2486
|
|
|
2223
2487
|
// Hero (structural)
|
|
2224
2488
|
rules['.bw-hero'] = {
|
|
@@ -2530,7 +2794,7 @@
|
|
|
2530
2794
|
'overflow-anchor': 'none',
|
|
2531
2795
|
'cursor': 'pointer',
|
|
2532
2796
|
'font-family': 'inherit',
|
|
2533
|
-
'transition': 'color 0.15s ease-
|
|
2797
|
+
'transition': 'color 0.15s ease-out, background-color 0.15s ease-out'
|
|
2534
2798
|
};
|
|
2535
2799
|
rules['.bw-accordion-button::after'] = {
|
|
2536
2800
|
'flex-shrink': '0',
|
|
@@ -2540,7 +2804,7 @@
|
|
|
2540
2804
|
'content': '""',
|
|
2541
2805
|
'background-repeat': 'no-repeat',
|
|
2542
2806
|
'background-size': '1.25rem',
|
|
2543
|
-
'transition': 'transform 0.2s ease-
|
|
2807
|
+
'transition': 'transform 0.2s ease-out'
|
|
2544
2808
|
};
|
|
2545
2809
|
rules['.bw-accordion-button:not(.bw-collapsed)::after'] = {
|
|
2546
2810
|
'transform': 'rotate(-180deg)'
|
|
@@ -2559,7 +2823,9 @@
|
|
|
2559
2823
|
|
|
2560
2824
|
// Modal (structural)
|
|
2561
2825
|
rules['.bw-modal'] = {
|
|
2562
|
-
'display': '
|
|
2826
|
+
'display': 'flex',
|
|
2827
|
+
'align-items': 'center',
|
|
2828
|
+
'justify-content': 'center',
|
|
2563
2829
|
'position': 'fixed',
|
|
2564
2830
|
'top': '0',
|
|
2565
2831
|
'left': '0',
|
|
@@ -2569,13 +2835,14 @@
|
|
|
2569
2835
|
'overflow-x': 'hidden',
|
|
2570
2836
|
'overflow-y': 'auto',
|
|
2571
2837
|
'opacity': '0',
|
|
2572
|
-
'
|
|
2838
|
+
'visibility': 'hidden',
|
|
2839
|
+
'pointer-events': 'none',
|
|
2840
|
+
'transition': 'opacity 0.2s ease, visibility 0.2s ease'
|
|
2573
2841
|
};
|
|
2574
2842
|
rules['.bw-modal.bw-modal-show'] = {
|
|
2575
|
-
'
|
|
2576
|
-
'
|
|
2577
|
-
'
|
|
2578
|
-
'opacity': '1'
|
|
2843
|
+
'opacity': '1',
|
|
2844
|
+
'visibility': 'visible',
|
|
2845
|
+
'pointer-events': 'auto'
|
|
2579
2846
|
};
|
|
2580
2847
|
rules['.bw-modal-dialog'] = {
|
|
2581
2848
|
'position': 'relative',
|
|
@@ -2642,7 +2909,7 @@
|
|
|
2642
2909
|
};
|
|
2643
2910
|
rules['.bw-carousel-track'] = {
|
|
2644
2911
|
'display': 'flex',
|
|
2645
|
-
'transition': 'transform 0.
|
|
2912
|
+
'transition': 'transform 0.3s ease-out',
|
|
2646
2913
|
'height': '100%'
|
|
2647
2914
|
};
|
|
2648
2915
|
rules['.bw-carousel-slide'] = {
|
|
@@ -2772,15 +3039,23 @@
|
|
|
2772
3039
|
'top': '100%',
|
|
2773
3040
|
'left': '0',
|
|
2774
3041
|
'z-index': '1000',
|
|
2775
|
-
'display': '
|
|
3042
|
+
'display': 'block',
|
|
2776
3043
|
'min-width': '10rem',
|
|
2777
3044
|
'padding': '0.5rem 0',
|
|
2778
3045
|
'margin': '0.125rem 0 0',
|
|
2779
3046
|
'background-clip': 'padding-box',
|
|
2780
|
-
'border-radius': '6px'
|
|
3047
|
+
'border-radius': '6px',
|
|
3048
|
+
'opacity': '0',
|
|
3049
|
+
'visibility': 'hidden',
|
|
3050
|
+
'transform': 'translateY(-4px)',
|
|
3051
|
+
'pointer-events': 'none',
|
|
3052
|
+
'transition': 'opacity 0.15s ease, transform 0.15s ease, visibility 0.15s ease'
|
|
2781
3053
|
};
|
|
2782
3054
|
rules['.bw-dropdown-menu.bw-dropdown-show'] = {
|
|
2783
|
-
'
|
|
3055
|
+
'opacity': '1',
|
|
3056
|
+
'visibility': 'visible',
|
|
3057
|
+
'transform': 'translateY(0)',
|
|
3058
|
+
'pointer-events': 'auto'
|
|
2784
3059
|
};
|
|
2785
3060
|
rules['.bw-dropdown-menu-end'] = {
|
|
2786
3061
|
'left': 'auto',
|
|
@@ -2800,6 +3075,10 @@
|
|
|
2800
3075
|
'font-size': '0.9375rem',
|
|
2801
3076
|
'transition': 'background-color 0.15s, color 0.15s'
|
|
2802
3077
|
};
|
|
3078
|
+
rules['.bw-dropdown-item:focus-visible'] = {
|
|
3079
|
+
'outline': '2px solid currentColor',
|
|
3080
|
+
'outline-offset': '-2px'
|
|
3081
|
+
};
|
|
2803
3082
|
rules['.bw-dropdown-divider'] = {
|
|
2804
3083
|
'height': '0',
|
|
2805
3084
|
'margin': '0.5rem 0',
|
|
@@ -2820,7 +3099,7 @@
|
|
|
2820
3099
|
'background-position': 'left center',
|
|
2821
3100
|
'background-repeat': 'no-repeat',
|
|
2822
3101
|
'background-size': 'contain',
|
|
2823
|
-
'transition': 'background-position 0.15s ease-
|
|
3102
|
+
'transition': 'background-position 0.15s ease-out, background-color 0.15s ease-out',
|
|
2824
3103
|
'cursor': 'pointer'
|
|
2825
3104
|
};
|
|
2826
3105
|
rules['.bw-form-switch .bw-switch-input:checked'] = {
|
|
@@ -2893,6 +3172,401 @@
|
|
|
2893
3172
|
'font-size': '1.5rem'
|
|
2894
3173
|
};
|
|
2895
3174
|
|
|
3175
|
+
// Stat card (structural)
|
|
3176
|
+
rules['.bw-stat-card'] = {
|
|
3177
|
+
'border-radius': '8px',
|
|
3178
|
+
'padding': '1.25rem',
|
|
3179
|
+
'border-left': '4px solid transparent',
|
|
3180
|
+
'transition': 'box-shadow 0.15s ease-out, transform 0.15s ease-out'
|
|
3181
|
+
};
|
|
3182
|
+
rules['.bw-stat-card:hover'] = {
|
|
3183
|
+
'transform': 'translateY(-1px)'
|
|
3184
|
+
};
|
|
3185
|
+
rules['.bw-stat-icon'] = {
|
|
3186
|
+
'font-size': '1.5rem',
|
|
3187
|
+
'margin-bottom': '0.5rem'
|
|
3188
|
+
};
|
|
3189
|
+
rules['.bw-stat-value'] = {
|
|
3190
|
+
'font-size': '2rem',
|
|
3191
|
+
'font-weight': '700',
|
|
3192
|
+
'line-height': '1.2'
|
|
3193
|
+
};
|
|
3194
|
+
rules['.bw-stat-label'] = {
|
|
3195
|
+
'font-size': '0.875rem',
|
|
3196
|
+
'margin-top': '0.25rem'
|
|
3197
|
+
};
|
|
3198
|
+
rules['.bw-stat-change'] = {
|
|
3199
|
+
'font-size': '0.875rem',
|
|
3200
|
+
'font-weight': '500',
|
|
3201
|
+
'margin-top': '0.5rem'
|
|
3202
|
+
};
|
|
3203
|
+
|
|
3204
|
+
// Tooltip (structural)
|
|
3205
|
+
rules['.bw-tooltip-wrapper'] = {
|
|
3206
|
+
'position': 'relative',
|
|
3207
|
+
'display': 'inline-block'
|
|
3208
|
+
};
|
|
3209
|
+
rules['.bw-tooltip'] = {
|
|
3210
|
+
'position': 'absolute',
|
|
3211
|
+
'z-index': '999',
|
|
3212
|
+
'padding': '0.375rem 0.75rem',
|
|
3213
|
+
'border-radius': '4px',
|
|
3214
|
+
'font-size': '0.875rem',
|
|
3215
|
+
'white-space': 'nowrap',
|
|
3216
|
+
'pointer-events': 'none',
|
|
3217
|
+
'opacity': '0',
|
|
3218
|
+
'visibility': 'hidden',
|
|
3219
|
+
'transition': 'opacity 0.15s ease, visibility 0.15s ease, transform 0.15s ease'
|
|
3220
|
+
};
|
|
3221
|
+
rules['.bw-tooltip.bw-tooltip-show'] = {
|
|
3222
|
+
'opacity': '1',
|
|
3223
|
+
'visibility': 'visible'
|
|
3224
|
+
};
|
|
3225
|
+
rules['.bw-tooltip-top'] = {
|
|
3226
|
+
'bottom': '100%',
|
|
3227
|
+
'left': '50%',
|
|
3228
|
+
'transform': 'translateX(-50%) translateY(-4px)',
|
|
3229
|
+
'margin-bottom': '4px'
|
|
3230
|
+
};
|
|
3231
|
+
rules['.bw-tooltip-top.bw-tooltip-show'] = {
|
|
3232
|
+
'transform': 'translateX(-50%) translateY(0)'
|
|
3233
|
+
};
|
|
3234
|
+
rules['.bw-tooltip-bottom'] = {
|
|
3235
|
+
'top': '100%',
|
|
3236
|
+
'left': '50%',
|
|
3237
|
+
'transform': 'translateX(-50%) translateY(4px)',
|
|
3238
|
+
'margin-top': '4px'
|
|
3239
|
+
};
|
|
3240
|
+
rules['.bw-tooltip-bottom.bw-tooltip-show'] = {
|
|
3241
|
+
'transform': 'translateX(-50%) translateY(0)'
|
|
3242
|
+
};
|
|
3243
|
+
rules['.bw-tooltip-left'] = {
|
|
3244
|
+
'right': '100%',
|
|
3245
|
+
'top': '50%',
|
|
3246
|
+
'transform': 'translateY(-50%) translateX(-4px)',
|
|
3247
|
+
'margin-right': '4px'
|
|
3248
|
+
};
|
|
3249
|
+
rules['.bw-tooltip-left.bw-tooltip-show'] = {
|
|
3250
|
+
'transform': 'translateY(-50%) translateX(0)'
|
|
3251
|
+
};
|
|
3252
|
+
rules['.bw-tooltip-right'] = {
|
|
3253
|
+
'left': '100%',
|
|
3254
|
+
'top': '50%',
|
|
3255
|
+
'transform': 'translateY(-50%) translateX(4px)',
|
|
3256
|
+
'margin-left': '4px'
|
|
3257
|
+
};
|
|
3258
|
+
rules['.bw-tooltip-right.bw-tooltip-show'] = {
|
|
3259
|
+
'transform': 'translateY(-50%) translateX(0)'
|
|
3260
|
+
};
|
|
3261
|
+
|
|
3262
|
+
// Search input (structural)
|
|
3263
|
+
rules['.bw-search-input'] = {
|
|
3264
|
+
'position': 'relative',
|
|
3265
|
+
'display': 'flex',
|
|
3266
|
+
'align-items': 'center'
|
|
3267
|
+
};
|
|
3268
|
+
rules['.bw-search-input .bw-search-field'] = {
|
|
3269
|
+
'padding-right': '2.5rem'
|
|
3270
|
+
};
|
|
3271
|
+
rules['.bw-search-clear'] = {
|
|
3272
|
+
'position': 'absolute',
|
|
3273
|
+
'right': '0.5rem',
|
|
3274
|
+
'display': 'flex',
|
|
3275
|
+
'align-items': 'center',
|
|
3276
|
+
'justify-content': 'center',
|
|
3277
|
+
'width': '1.5rem',
|
|
3278
|
+
'height': '1.5rem',
|
|
3279
|
+
'border': 'none',
|
|
3280
|
+
'background': 'none',
|
|
3281
|
+
'font-size': '1.25rem',
|
|
3282
|
+
'cursor': 'pointer',
|
|
3283
|
+
'padding': '0',
|
|
3284
|
+
'border-radius': '50%',
|
|
3285
|
+
'transition': 'color 0.15s ease-out'
|
|
3286
|
+
};
|
|
3287
|
+
|
|
3288
|
+
// Range slider (structural)
|
|
3289
|
+
rules['.bw-range-wrapper'] = {
|
|
3290
|
+
'margin-bottom': '1rem'
|
|
3291
|
+
};
|
|
3292
|
+
rules['.bw-range-label'] = {
|
|
3293
|
+
'display': 'flex',
|
|
3294
|
+
'justify-content': 'space-between',
|
|
3295
|
+
'align-items': 'center',
|
|
3296
|
+
'margin-bottom': '0.5rem',
|
|
3297
|
+
'font-size': '0.875rem',
|
|
3298
|
+
'font-weight': '500'
|
|
3299
|
+
};
|
|
3300
|
+
rules['.bw-range-value'] = {
|
|
3301
|
+
'font-weight': '600'
|
|
3302
|
+
};
|
|
3303
|
+
rules['.bw-range'] = {
|
|
3304
|
+
'width': '100%',
|
|
3305
|
+
'height': '0.5rem',
|
|
3306
|
+
'padding': '0',
|
|
3307
|
+
'appearance': 'none',
|
|
3308
|
+
'border': 'none',
|
|
3309
|
+
'border-radius': '0.25rem',
|
|
3310
|
+
'cursor': 'pointer',
|
|
3311
|
+
'outline': 'none'
|
|
3312
|
+
};
|
|
3313
|
+
rules['.bw-range:disabled'] = {
|
|
3314
|
+
'opacity': '0.5',
|
|
3315
|
+
'cursor': 'not-allowed'
|
|
3316
|
+
};
|
|
3317
|
+
|
|
3318
|
+
// Media object (structural)
|
|
3319
|
+
rules['.bw-media'] = {
|
|
3320
|
+
'display': 'flex',
|
|
3321
|
+
'align-items': 'flex-start',
|
|
3322
|
+
'gap': '1rem'
|
|
3323
|
+
};
|
|
3324
|
+
rules['.bw-media-reverse'] = {
|
|
3325
|
+
'flex-direction': 'row-reverse'
|
|
3326
|
+
};
|
|
3327
|
+
rules['.bw-media-img'] = {
|
|
3328
|
+
'border-radius': '50%',
|
|
3329
|
+
'object-fit': 'cover',
|
|
3330
|
+
'flex-shrink': '0'
|
|
3331
|
+
};
|
|
3332
|
+
rules['.bw-media-body'] = {
|
|
3333
|
+
'flex': '1',
|
|
3334
|
+
'min-width': '0'
|
|
3335
|
+
};
|
|
3336
|
+
rules['.bw-media-title'] = {
|
|
3337
|
+
'margin': '0 0 0.25rem 0',
|
|
3338
|
+
'font-size': '1rem',
|
|
3339
|
+
'font-weight': '600',
|
|
3340
|
+
'line-height': '1.3'
|
|
3341
|
+
};
|
|
3342
|
+
|
|
3343
|
+
// File upload (structural)
|
|
3344
|
+
rules['.bw-file-upload'] = {
|
|
3345
|
+
'display': 'flex',
|
|
3346
|
+
'flex-direction': 'column',
|
|
3347
|
+
'align-items': 'center',
|
|
3348
|
+
'justify-content': 'center',
|
|
3349
|
+
'padding': '2rem',
|
|
3350
|
+
'border': '2px dashed transparent',
|
|
3351
|
+
'border-radius': '8px',
|
|
3352
|
+
'cursor': 'pointer',
|
|
3353
|
+
'text-align': 'center',
|
|
3354
|
+
'position': 'relative',
|
|
3355
|
+
'transition': 'border-color 0.15s ease-out, background-color 0.15s ease-out'
|
|
3356
|
+
};
|
|
3357
|
+
rules['.bw-file-upload-icon'] = {
|
|
3358
|
+
'font-size': '2rem',
|
|
3359
|
+
'margin-bottom': '0.5rem'
|
|
3360
|
+
};
|
|
3361
|
+
rules['.bw-file-upload-text'] = {
|
|
3362
|
+
'font-size': '0.875rem'
|
|
3363
|
+
};
|
|
3364
|
+
rules['.bw-file-upload-input'] = {
|
|
3365
|
+
'position': 'absolute',
|
|
3366
|
+
'width': '1px',
|
|
3367
|
+
'height': '1px',
|
|
3368
|
+
'padding': '0',
|
|
3369
|
+
'margin': '-1px',
|
|
3370
|
+
'overflow': 'hidden',
|
|
3371
|
+
'clip': 'rect(0,0,0,0)',
|
|
3372
|
+
'border': '0'
|
|
3373
|
+
};
|
|
3374
|
+
|
|
3375
|
+
// Timeline (structural)
|
|
3376
|
+
rules['.bw-timeline'] = {
|
|
3377
|
+
'position': 'relative',
|
|
3378
|
+
'padding-left': '2rem'
|
|
3379
|
+
};
|
|
3380
|
+
rules['.bw-timeline-item'] = {
|
|
3381
|
+
'position': 'relative',
|
|
3382
|
+
'padding-bottom': '1.5rem'
|
|
3383
|
+
};
|
|
3384
|
+
rules['.bw-timeline-item:last-child'] = {
|
|
3385
|
+
'padding-bottom': '0'
|
|
3386
|
+
};
|
|
3387
|
+
rules['.bw-timeline-marker'] = {
|
|
3388
|
+
'position': 'absolute',
|
|
3389
|
+
'left': '-1.75rem',
|
|
3390
|
+
'top': '0.25rem',
|
|
3391
|
+
'width': '0.75rem',
|
|
3392
|
+
'height': '0.75rem',
|
|
3393
|
+
'border-radius': '50%'
|
|
3394
|
+
};
|
|
3395
|
+
rules['.bw-timeline-content'] = {
|
|
3396
|
+
'padding-left': '0.5rem'
|
|
3397
|
+
};
|
|
3398
|
+
rules['.bw-timeline-date'] = {
|
|
3399
|
+
'font-size': '0.75rem',
|
|
3400
|
+
'margin-bottom': '0.25rem',
|
|
3401
|
+
'font-weight': '500'
|
|
3402
|
+
};
|
|
3403
|
+
rules['.bw-timeline-title'] = {
|
|
3404
|
+
'font-size': '1rem',
|
|
3405
|
+
'font-weight': '600',
|
|
3406
|
+
'margin': '0 0 0.25rem 0',
|
|
3407
|
+
'line-height': '1.3'
|
|
3408
|
+
};
|
|
3409
|
+
rules['.bw-timeline-text'] = {
|
|
3410
|
+
'font-size': '0.875rem',
|
|
3411
|
+
'margin': '0',
|
|
3412
|
+
'line-height': '1.5'
|
|
3413
|
+
};
|
|
3414
|
+
|
|
3415
|
+
// Stepper (structural)
|
|
3416
|
+
rules['.bw-stepper'] = {
|
|
3417
|
+
'display': 'flex',
|
|
3418
|
+
'gap': '0'
|
|
3419
|
+
};
|
|
3420
|
+
rules['.bw-step'] = {
|
|
3421
|
+
'flex': '1',
|
|
3422
|
+
'display': 'flex',
|
|
3423
|
+
'flex-direction': 'column',
|
|
3424
|
+
'align-items': 'center',
|
|
3425
|
+
'text-align': 'center',
|
|
3426
|
+
'position': 'relative'
|
|
3427
|
+
};
|
|
3428
|
+
rules['.bw-step-indicator'] = {
|
|
3429
|
+
'width': '2rem',
|
|
3430
|
+
'height': '2rem',
|
|
3431
|
+
'border-radius': '50%',
|
|
3432
|
+
'display': 'flex',
|
|
3433
|
+
'align-items': 'center',
|
|
3434
|
+
'justify-content': 'center',
|
|
3435
|
+
'font-size': '0.875rem',
|
|
3436
|
+
'font-weight': '600',
|
|
3437
|
+
'position': 'relative',
|
|
3438
|
+
'z-index': '1',
|
|
3439
|
+
'transition': 'background-color 0.2s ease-out, color 0.2s ease-out'
|
|
3440
|
+
};
|
|
3441
|
+
rules['.bw-step-body'] = {
|
|
3442
|
+
'margin-top': '0.5rem'
|
|
3443
|
+
};
|
|
3444
|
+
rules['.bw-step-label'] = {
|
|
3445
|
+
'font-size': '0.875rem',
|
|
3446
|
+
'font-weight': '500'
|
|
3447
|
+
};
|
|
3448
|
+
rules['.bw-step-description'] = {
|
|
3449
|
+
'font-size': '0.75rem',
|
|
3450
|
+
'margin-top': '0.125rem'
|
|
3451
|
+
};
|
|
3452
|
+
|
|
3453
|
+
// Chip input (structural)
|
|
3454
|
+
rules['.bw-chip-input'] = {
|
|
3455
|
+
'display': 'flex',
|
|
3456
|
+
'flex-wrap': 'wrap',
|
|
3457
|
+
'align-items': 'center',
|
|
3458
|
+
'gap': '0.375rem',
|
|
3459
|
+
'padding': '0.375rem 0.5rem',
|
|
3460
|
+
'border-radius': '6px',
|
|
3461
|
+
'min-height': '2.5rem',
|
|
3462
|
+
'cursor': 'text',
|
|
3463
|
+
'transition': 'border-color 0.15s ease-out, box-shadow 0.15s ease-out'
|
|
3464
|
+
};
|
|
3465
|
+
rules['.bw-chip'] = {
|
|
3466
|
+
'display': 'inline-flex',
|
|
3467
|
+
'align-items': 'center',
|
|
3468
|
+
'gap': '0.25rem',
|
|
3469
|
+
'padding': '0.125rem 0.5rem',
|
|
3470
|
+
'border-radius': '1rem',
|
|
3471
|
+
'font-size': '0.8125rem',
|
|
3472
|
+
'line-height': '1.5',
|
|
3473
|
+
'white-space': 'nowrap'
|
|
3474
|
+
};
|
|
3475
|
+
rules['.bw-chip-remove'] = {
|
|
3476
|
+
'display': 'inline-flex',
|
|
3477
|
+
'align-items': 'center',
|
|
3478
|
+
'justify-content': 'center',
|
|
3479
|
+
'width': '1rem',
|
|
3480
|
+
'height': '1rem',
|
|
3481
|
+
'border': 'none',
|
|
3482
|
+
'background': 'none',
|
|
3483
|
+
'font-size': '0.875rem',
|
|
3484
|
+
'cursor': 'pointer',
|
|
3485
|
+
'padding': '0',
|
|
3486
|
+
'border-radius': '50%',
|
|
3487
|
+
'transition': 'color 0.15s ease-out, background-color 0.15s ease-out'
|
|
3488
|
+
};
|
|
3489
|
+
rules['.bw-chip-field'] = {
|
|
3490
|
+
'flex': '1',
|
|
3491
|
+
'min-width': '80px',
|
|
3492
|
+
'border': 'none',
|
|
3493
|
+
'outline': 'none',
|
|
3494
|
+
'font-size': '0.875rem',
|
|
3495
|
+
'padding': '0.125rem 0',
|
|
3496
|
+
'background': 'transparent'
|
|
3497
|
+
};
|
|
3498
|
+
|
|
3499
|
+
// Popover (structural)
|
|
3500
|
+
rules['.bw-popover-wrapper'] = {
|
|
3501
|
+
'position': 'relative',
|
|
3502
|
+
'display': 'inline-block'
|
|
3503
|
+
};
|
|
3504
|
+
rules['.bw-popover-trigger'] = {
|
|
3505
|
+
'cursor': 'pointer'
|
|
3506
|
+
};
|
|
3507
|
+
rules['.bw-popover'] = {
|
|
3508
|
+
'position': 'absolute',
|
|
3509
|
+
'z-index': '1000',
|
|
3510
|
+
'min-width': '200px',
|
|
3511
|
+
'max-width': '320px',
|
|
3512
|
+
'border-radius': '8px',
|
|
3513
|
+
'pointer-events': 'none',
|
|
3514
|
+
'opacity': '0',
|
|
3515
|
+
'visibility': 'hidden',
|
|
3516
|
+
'transition': 'opacity 0.15s ease, visibility 0.15s ease, transform 0.15s ease'
|
|
3517
|
+
};
|
|
3518
|
+
rules['.bw-popover.bw-popover-show'] = {
|
|
3519
|
+
'opacity': '1',
|
|
3520
|
+
'visibility': 'visible',
|
|
3521
|
+
'pointer-events': 'auto'
|
|
3522
|
+
};
|
|
3523
|
+
rules['.bw-popover-header'] = {
|
|
3524
|
+
'padding': '0.625rem 0.875rem',
|
|
3525
|
+
'font-weight': '600',
|
|
3526
|
+
'font-size': '0.9375rem'
|
|
3527
|
+
};
|
|
3528
|
+
rules['.bw-popover-body'] = {
|
|
3529
|
+
'padding': '0.75rem 0.875rem',
|
|
3530
|
+
'font-size': '0.875rem',
|
|
3531
|
+
'line-height': '1.5'
|
|
3532
|
+
};
|
|
3533
|
+
rules['.bw-popover-top'] = {
|
|
3534
|
+
'bottom': '100%',
|
|
3535
|
+
'left': '50%',
|
|
3536
|
+
'transform': 'translateX(-50%) translateY(-8px)',
|
|
3537
|
+
'margin-bottom': '8px'
|
|
3538
|
+
};
|
|
3539
|
+
rules['.bw-popover-top.bw-popover-show'] = {
|
|
3540
|
+
'transform': 'translateX(-50%) translateY(0)'
|
|
3541
|
+
};
|
|
3542
|
+
rules['.bw-popover-bottom'] = {
|
|
3543
|
+
'top': '100%',
|
|
3544
|
+
'left': '50%',
|
|
3545
|
+
'transform': 'translateX(-50%) translateY(8px)',
|
|
3546
|
+
'margin-top': '8px'
|
|
3547
|
+
};
|
|
3548
|
+
rules['.bw-popover-bottom.bw-popover-show'] = {
|
|
3549
|
+
'transform': 'translateX(-50%) translateY(0)'
|
|
3550
|
+
};
|
|
3551
|
+
rules['.bw-popover-left'] = {
|
|
3552
|
+
'right': '100%',
|
|
3553
|
+
'top': '50%',
|
|
3554
|
+
'transform': 'translateY(-50%) translateX(-8px)',
|
|
3555
|
+
'margin-right': '8px'
|
|
3556
|
+
};
|
|
3557
|
+
rules['.bw-popover-left.bw-popover-show'] = {
|
|
3558
|
+
'transform': 'translateY(-50%) translateX(0)'
|
|
3559
|
+
};
|
|
3560
|
+
rules['.bw-popover-right'] = {
|
|
3561
|
+
'left': '100%',
|
|
3562
|
+
'top': '50%',
|
|
3563
|
+
'transform': 'translateY(-50%) translateX(8px)',
|
|
3564
|
+
'margin-left': '8px'
|
|
3565
|
+
};
|
|
3566
|
+
rules['.bw-popover-right.bw-popover-show'] = {
|
|
3567
|
+
'transform': 'translateY(-50%) translateX(0)'
|
|
3568
|
+
};
|
|
3569
|
+
|
|
2896
3570
|
// Bar chart (structural)
|
|
2897
3571
|
rules['.bw-bar-chart-container'] = {
|
|
2898
3572
|
'padding': '1rem',
|
|
@@ -2916,7 +3590,7 @@
|
|
|
2916
3590
|
rules['.bw-bar'] = {
|
|
2917
3591
|
'width': '100%',
|
|
2918
3592
|
'border-radius': '3px 3px 0 0',
|
|
2919
|
-
'transition': 'height 0.
|
|
3593
|
+
'transition': 'height 0.3s ease-out',
|
|
2920
3594
|
'min-height': '4px'
|
|
2921
3595
|
};
|
|
2922
3596
|
rules['.bw-bar:hover'] = {
|
|
@@ -3215,6 +3889,16 @@
|
|
|
3215
3889
|
|
|
3216
3890
|
// Responsive grid
|
|
3217
3891
|
Object.assign(rules, defaultStyles.responsive);
|
|
3892
|
+
|
|
3893
|
+
// Accessibility: reduce motion for users who prefer it
|
|
3894
|
+
rules['@media (prefers-reduced-motion: reduce)'] = {
|
|
3895
|
+
'*, *::before, *::after': {
|
|
3896
|
+
'animation-duration': '0.01ms !important',
|
|
3897
|
+
'animation-iteration-count': '1 !important',
|
|
3898
|
+
'transition-duration': '0.01ms !important',
|
|
3899
|
+
'scroll-behavior': 'auto !important'
|
|
3900
|
+
}
|
|
3901
|
+
};
|
|
3218
3902
|
return addUnderscoreAliases(rules);
|
|
3219
3903
|
}
|
|
3220
3904
|
|
|
@@ -3223,9 +3907,25 @@
|
|
|
3223
3907
|
// =========================================================================
|
|
3224
3908
|
|
|
3225
3909
|
/**
|
|
3226
|
-
* Add underscore aliases for all bw
|
|
3910
|
+
* Add underscore aliases for all `.bw-` selectors.
|
|
3911
|
+
*
|
|
3912
|
+
* CSS CLASS NAMING CONVENTION:
|
|
3913
|
+
*
|
|
3914
|
+
* Canonical form: `.bw-btn`, `.bw-card`, `.bw-table-hover` (hyphens)
|
|
3915
|
+
* Underscore alias: `.bw_btn`, `.bw_card`, `.bw_table_hover` (underscores)
|
|
3916
|
+
*
|
|
3917
|
+
* Both forms are valid in HTML and produce identical results. The hyphen
|
|
3918
|
+
* form is canonical (used in docs, generated CSS, component output).
|
|
3919
|
+
* Underscore aliases exist because:
|
|
3920
|
+
* 1. TACO attribute keys use underscores (`bw_id`, `bw_meta`) — no
|
|
3921
|
+
* quoting needed in JS object literals
|
|
3922
|
+
* 2. Some users prefer underscores for consistency with JS identifiers
|
|
3923
|
+
*
|
|
3924
|
+
* Use `bw.normalizeClass()` to convert underscore classes to canonical
|
|
3925
|
+
* hyphen form at runtime if needed.
|
|
3926
|
+
*
|
|
3227
3927
|
* @param {Object} rules - CSS rules object
|
|
3228
|
-
* @returns {Object}
|
|
3928
|
+
* @returns {Object} Rules with underscore aliases added (both forms work)
|
|
3229
3929
|
*/
|
|
3230
3930
|
function addUnderscoreAliases(rules) {
|
|
3231
3931
|
var result = {};
|
|
@@ -3245,6 +3945,27 @@
|
|
|
3245
3945
|
// =========================================================================
|
|
3246
3946
|
// Theme tokens (backwards compatible)
|
|
3247
3947
|
// =========================================================================
|
|
3948
|
+
//
|
|
3949
|
+
// DESIGN NOTE — Why no CSS custom properties (CSS variables)?
|
|
3950
|
+
//
|
|
3951
|
+
// Bitwrench targets IE11 as Tier 1 (see dev/bw2x-compatibility.md).
|
|
3952
|
+
// CSS custom properties (var(--color-primary)) are not supported in IE11.
|
|
3953
|
+
//
|
|
3954
|
+
// Instead, bitwrench uses class-scoped CSS generation:
|
|
3955
|
+
// 1. `defaultStyles.*` provides hardcoded cosmetic defaults
|
|
3956
|
+
// 2. `generateTheme(name, config)` generates a complete set of
|
|
3957
|
+
// class-scoped CSS rules from 3 seed colors (primary, secondary,
|
|
3958
|
+
// tertiary) — all components are restyled with the new palette
|
|
3959
|
+
// 3. `generateAlternateCSS()` produces the alternate (dark/light)
|
|
3960
|
+
// variant scoped under `.bw-theme-alt`
|
|
3961
|
+
//
|
|
3962
|
+
// This achieves full theme customization without CSS variables:
|
|
3963
|
+
// bw.generateTheme('ocean', { primary: '#006666', secondary: '#cc6633' })
|
|
3964
|
+
// → generates .ocean .bw-btn-primary { background: #006666; } etc.
|
|
3965
|
+
//
|
|
3966
|
+
// When IE11 support is dropped, CSS custom properties can be added as
|
|
3967
|
+
// an optimization (one rule with var() instead of many scoped rules).
|
|
3968
|
+
// The generateTheme() API stays the same — only the output format changes.
|
|
3248
3969
|
|
|
3249
3970
|
var theme = {
|
|
3250
3971
|
colors: {
|
|
@@ -3252,8 +3973,8 @@
|
|
|
3252
3973
|
secondary: '#6c757d',
|
|
3253
3974
|
success: '#198754',
|
|
3254
3975
|
danger: '#dc3545',
|
|
3255
|
-
warning: '#
|
|
3256
|
-
info: '#
|
|
3976
|
+
warning: '#b38600',
|
|
3977
|
+
info: '#0891b2',
|
|
3257
3978
|
light: '#f8f9fa',
|
|
3258
3979
|
dark: '#212529',
|
|
3259
3980
|
white: '#fff',
|
|
@@ -3288,214 +4009,61 @@
|
|
|
3288
4009
|
'4xl': '2.25rem',
|
|
3289
4010
|
'5xl': '3rem'
|
|
3290
4011
|
}
|
|
3291
|
-
}
|
|
3292
|
-
darkMode: false
|
|
4012
|
+
}
|
|
3293
4013
|
};
|
|
3294
4014
|
|
|
3295
4015
|
/**
|
|
3296
|
-
* Generate
|
|
3297
|
-
*
|
|
4016
|
+
* Generate alternate-palette CSS scoped under `.bw-theme-alt`.
|
|
4017
|
+
* Uses the same `generateThemedCSS()` pipeline as the primary palette —
|
|
4018
|
+
* both sides go through identical code paths.
|
|
3298
4019
|
*
|
|
3299
|
-
* @param {
|
|
3300
|
-
* @
|
|
4020
|
+
* @param {string} name - Theme scope name (e.g. 'ocean'). '' for global.
|
|
4021
|
+
* @param {Object} altPalette - From derivePalette(deriveAlternateConfig(...))
|
|
4022
|
+
* @param {Object} layout - From resolveLayout()
|
|
4023
|
+
* @returns {Object} CSS rules object scoped under .bw-theme-alt (+ optional .name)
|
|
3301
4024
|
*/
|
|
3302
|
-
function
|
|
3303
|
-
|
|
3304
|
-
var
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
var
|
|
3308
|
-
var
|
|
3309
|
-
var
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
},
|
|
3334
|
-
'.bw-dark .bw-card-title': {
|
|
3335
|
-
'color': textColor
|
|
3336
|
-
},
|
|
3337
|
-
'.bw-dark .bw-navbar': {
|
|
3338
|
-
'background-color': surfaceBg,
|
|
3339
|
-
'border-bottom-color': borderColor
|
|
3340
|
-
},
|
|
3341
|
-
'.bw-dark .bw-navbar-brand': {
|
|
3342
|
-
'color': textColor
|
|
3343
|
-
},
|
|
3344
|
-
'.bw-dark .bw-navbar-nav .bw-nav-link': {
|
|
3345
|
-
'color': adjustLightness(textColor, -15)
|
|
3346
|
-
},
|
|
3347
|
-
'.bw-dark .bw-navbar-nav .bw-nav-link:hover': {
|
|
3348
|
-
'color': textColor
|
|
3349
|
-
},
|
|
3350
|
-
'.bw-dark .bw-form-control': {
|
|
3351
|
-
'background-color': surfaceBg,
|
|
3352
|
-
'border-color': borderColor,
|
|
3353
|
-
'color': textColor
|
|
3354
|
-
},
|
|
3355
|
-
'.bw-dark .bw-form-label': {
|
|
3356
|
-
'color': textColor
|
|
3357
|
-
},
|
|
3358
|
-
'.bw-dark .bw-form-text': {
|
|
3359
|
-
'color': adjustLightness(textColor, -20)
|
|
3360
|
-
},
|
|
3361
|
-
'.bw-dark .bw-table': {
|
|
3362
|
-
'color': textColor
|
|
3363
|
-
},
|
|
3364
|
-
'.bw-dark .bw-table > :not(caption) > * > *': {
|
|
3365
|
-
'border-bottom-color': borderColor
|
|
3366
|
-
},
|
|
3367
|
-
'.bw-dark .bw-table > thead > tr > *': {
|
|
3368
|
-
'background-color': bodyBg,
|
|
3369
|
-
'color': adjustLightness(textColor, -10),
|
|
3370
|
-
'border-bottom-color': borderColor
|
|
3371
|
-
},
|
|
3372
|
-
'.bw-dark .bw-table-striped > tbody > tr:nth-of-type(odd) > *': {
|
|
3373
|
-
'background-color': 'rgba(255, 255, 255, 0.05)'
|
|
3374
|
-
},
|
|
3375
|
-
'.bw-dark .bw-alert': {
|
|
3376
|
-
'border-color': borderColor
|
|
3377
|
-
},
|
|
3378
|
-
'.bw-dark .bw-list-group-item': {
|
|
3379
|
-
'background-color': surfaceBg,
|
|
3380
|
-
'border-color': borderColor,
|
|
3381
|
-
'color': textColor
|
|
3382
|
-
},
|
|
3383
|
-
'.bw-dark .bw-badge': {
|
|
3384
|
-
'color': textColor
|
|
3385
|
-
},
|
|
3386
|
-
'.bw-dark .bw-nav-tabs': {
|
|
3387
|
-
'border-bottom-color': borderColor
|
|
3388
|
-
},
|
|
3389
|
-
'.bw-dark .bw-nav-link': {
|
|
3390
|
-
'color': adjustLightness(textColor, -15)
|
|
3391
|
-
},
|
|
3392
|
-
'.bw-dark .bw-nav-tabs .bw-nav-link:hover': {
|
|
3393
|
-
'color': textColor,
|
|
3394
|
-
'border-bottom-color': borderColor
|
|
3395
|
-
},
|
|
3396
|
-
'.bw-dark .bw-pagination .bw-page-link': {
|
|
3397
|
-
'background-color': surfaceBg,
|
|
3398
|
-
'border-color': borderColor,
|
|
3399
|
-
'color': textColor
|
|
3400
|
-
},
|
|
3401
|
-
'.bw-dark .bw-breadcrumb-item + .bw-breadcrumb-item::before': {
|
|
3402
|
-
'color': adjustLightness(textColor, -20)
|
|
3403
|
-
},
|
|
3404
|
-
'.bw-dark .bw-breadcrumb-item.active': {
|
|
3405
|
-
'color': adjustLightness(textColor, -10)
|
|
3406
|
-
},
|
|
3407
|
-
'.bw-dark .bw-hero-light': {
|
|
3408
|
-
'background': surfaceBg,
|
|
3409
|
-
'color': textColor
|
|
3410
|
-
},
|
|
3411
|
-
'.bw-dark .bw-progress': {
|
|
3412
|
-
'background-color': surfaceBg
|
|
3413
|
-
},
|
|
3414
|
-
'.bw-dark .bw-section-subtitle': {
|
|
3415
|
-
'color': adjustLightness(textColor, -15)
|
|
3416
|
-
},
|
|
3417
|
-
'.bw-dark .bw-close': {
|
|
3418
|
-
'color': textColor
|
|
3419
|
-
},
|
|
3420
|
-
'.bw-dark .bw-accordion-item': {
|
|
3421
|
-
'background-color': surfaceBg,
|
|
3422
|
-
'border-color': borderColor
|
|
3423
|
-
},
|
|
3424
|
-
'.bw-dark .bw-accordion-button': {
|
|
3425
|
-
'color': textColor
|
|
3426
|
-
},
|
|
3427
|
-
'.bw-dark .bw-accordion-button:not(.bw-collapsed)': {
|
|
3428
|
-
'color': '#7dd3e0',
|
|
3429
|
-
'background-color': 'rgba(125, 211, 224, 0.1)'
|
|
3430
|
-
},
|
|
3431
|
-
'.bw-dark .bw-accordion-button:hover': {
|
|
3432
|
-
'background-color': bodyBg
|
|
3433
|
-
},
|
|
3434
|
-
'.bw-dark .bw-accordion-button:not(.bw-collapsed):hover': {
|
|
3435
|
-
'background-color': 'rgba(125, 211, 224, 0.15)'
|
|
3436
|
-
},
|
|
3437
|
-
'.bw-dark .bw-accordion-button:focus-visible': {
|
|
3438
|
-
'box-shadow': '0 0 0 0.2rem rgba(125, 211, 224, 0.3)'
|
|
3439
|
-
},
|
|
3440
|
-
'.bw-dark .bw-accordion-body': {
|
|
3441
|
-
'border-top-color': borderColor
|
|
3442
|
-
},
|
|
3443
|
-
'.bw-dark .bw-carousel': {
|
|
3444
|
-
'background-color': bodyBg
|
|
3445
|
-
},
|
|
3446
|
-
'.bw-dark .bw-carousel-control': {
|
|
3447
|
-
'background-color': 'rgba(255,255,255,0.15)'
|
|
3448
|
-
},
|
|
3449
|
-
'.bw-dark .bw-carousel-control:hover': {
|
|
3450
|
-
'background-color': 'rgba(255,255,255,0.25)'
|
|
3451
|
-
},
|
|
3452
|
-
'.bw-dark .bw-modal-content': {
|
|
3453
|
-
'background-color': surfaceBg,
|
|
3454
|
-
'border-color': borderColor
|
|
3455
|
-
},
|
|
3456
|
-
'.bw-dark .bw-modal-header': {
|
|
3457
|
-
'border-bottom-color': borderColor
|
|
3458
|
-
},
|
|
3459
|
-
'.bw-dark .bw-modal-footer': {
|
|
3460
|
-
'border-top-color': borderColor
|
|
3461
|
-
},
|
|
3462
|
-
'.bw-dark .bw-modal-title': {
|
|
3463
|
-
'color': textColor
|
|
3464
|
-
},
|
|
3465
|
-
'.bw-dark .bw-toast': {
|
|
3466
|
-
'background-color': surfaceBg,
|
|
3467
|
-
'border-color': borderColor
|
|
3468
|
-
},
|
|
3469
|
-
'.bw-dark .bw-toast-header': {
|
|
3470
|
-
'border-bottom-color': borderColor,
|
|
3471
|
-
'color': textColor
|
|
3472
|
-
},
|
|
3473
|
-
'.bw-dark .bw-dropdown-menu': {
|
|
3474
|
-
'background-color': surfaceBg,
|
|
3475
|
-
'border-color': borderColor
|
|
3476
|
-
},
|
|
3477
|
-
'.bw-dark .bw-dropdown-item': {
|
|
3478
|
-
'color': textColor
|
|
3479
|
-
},
|
|
3480
|
-
'.bw-dark .bw-dropdown-item:hover': {
|
|
3481
|
-
'background-color': bodyBg
|
|
3482
|
-
},
|
|
3483
|
-
'.bw-dark .bw-dropdown-divider': {
|
|
3484
|
-
'border-top-color': borderColor
|
|
3485
|
-
},
|
|
3486
|
-
'.bw-dark .bw-skeleton': {
|
|
3487
|
-
'background': 'linear-gradient(90deg, ' + borderColor + ' 25%, ' + surfaceBg + ' 37%, ' + borderColor + ' 63%)'
|
|
3488
|
-
},
|
|
3489
|
-
'.bw-dark h1, .bw-dark h2, .bw-dark h3, .bw-dark h4, .bw-dark h5, .bw-dark h6': {
|
|
3490
|
-
'color': textColor
|
|
3491
|
-
},
|
|
3492
|
-
'@media (prefers-color-scheme: dark)': {
|
|
3493
|
-
':root.bw-auto-dark body': {
|
|
3494
|
-
'color': textColor,
|
|
3495
|
-
'background-color': bodyBg
|
|
4025
|
+
function generateAlternateCSS(name, altPalette, layout) {
|
|
4026
|
+
// Generate themed CSS using the same pipeline as primary
|
|
4027
|
+
var rawRules = generateThemedCSS('', altPalette, layout);
|
|
4028
|
+
|
|
4029
|
+
// Re-scope every selector under .bw-theme-alt (+ optional theme name)
|
|
4030
|
+
var altPrefix = name ? '.' + name + '.bw-theme-alt' : '.bw-theme-alt';
|
|
4031
|
+
var altRules = {};
|
|
4032
|
+
for (var sel in rawRules) {
|
|
4033
|
+
if (!rawRules.hasOwnProperty(sel)) continue;
|
|
4034
|
+
if (sel.charAt(0) === '@') {
|
|
4035
|
+
// @media / @keyframes — recurse into the block
|
|
4036
|
+
var innerBlock = rawRules[sel];
|
|
4037
|
+
var altInner = {};
|
|
4038
|
+
for (var innerSel in innerBlock) {
|
|
4039
|
+
if (!innerBlock.hasOwnProperty(innerSel)) continue;
|
|
4040
|
+
altInner[altPrefix + ' ' + innerSel] = innerBlock[innerSel];
|
|
4041
|
+
}
|
|
4042
|
+
altRules[sel] = altInner;
|
|
4043
|
+
} else {
|
|
4044
|
+
// Regular selector — prefix with alt scope
|
|
4045
|
+
// Handle comma-separated selectors
|
|
4046
|
+
var parts = sel.split(',');
|
|
4047
|
+
var scopedParts = [];
|
|
4048
|
+
for (var i = 0; i < parts.length; i++) {
|
|
4049
|
+
var s = parts[i].trim();
|
|
4050
|
+
// 'body' selector gets special treatment: .bw-theme-alt body
|
|
4051
|
+
if (s === 'body' || s.indexOf('body') === 0) {
|
|
4052
|
+
scopedParts.push(altPrefix + ' ' + s);
|
|
4053
|
+
} else {
|
|
4054
|
+
scopedParts.push(altPrefix + ' ' + s);
|
|
4055
|
+
}
|
|
3496
4056
|
}
|
|
4057
|
+
altRules[scopedParts.join(', ')] = rawRules[sel];
|
|
3497
4058
|
}
|
|
4059
|
+
}
|
|
4060
|
+
|
|
4061
|
+
// Add body-level overrides for the alternate surface
|
|
4062
|
+
altRules[altPrefix + ' body, :root' + altPrefix + ' body'] = {
|
|
4063
|
+
'color': altPalette.dark.base,
|
|
4064
|
+
'background-color': altPalette.light.base
|
|
3498
4065
|
};
|
|
4066
|
+
return altRules;
|
|
3499
4067
|
}
|
|
3500
4068
|
function deepMerge(target, source) {
|
|
3501
4069
|
for (var _i2 = 0, _Object$keys = Object.keys(source); _i2 < _Object$keys.length; _i2++) {
|
|
@@ -5263,8 +5831,10 @@
|
|
|
5263
5831
|
/**
|
|
5264
5832
|
* Generate responsive CSS with media query breakpoints.
|
|
5265
5833
|
*
|
|
5266
|
-
* Produces a CSS string with `@media` rules for
|
|
5267
|
-
*
|
|
5834
|
+
* Produces a CSS string with `@media (min-width)` rules for standard
|
|
5835
|
+
* breakpoints. These match the grid system and theme.breakpoints:
|
|
5836
|
+
* sm: 576px, md: 768px, lg: 992px, xl: 1200px
|
|
5837
|
+
* Pass the result to `bw.injectCSS()`.
|
|
5268
5838
|
*
|
|
5269
5839
|
* @param {string} selector - CSS selector
|
|
5270
5840
|
* @param {Object} breakpoints - Object with keys: base, sm, md, lg, xl
|
|
@@ -5282,10 +5852,10 @@
|
|
|
5282
5852
|
*/
|
|
5283
5853
|
bw.responsive = function (selector, breakpoints) {
|
|
5284
5854
|
var sizes = {
|
|
5285
|
-
sm: '
|
|
5855
|
+
sm: '576px',
|
|
5286
5856
|
md: '768px',
|
|
5287
|
-
lg: '
|
|
5288
|
-
xl: '
|
|
5857
|
+
lg: '992px',
|
|
5858
|
+
xl: '1200px'
|
|
5289
5859
|
};
|
|
5290
5860
|
var parts = [];
|
|
5291
5861
|
Object.keys(breakpoints).forEach(function (key) {
|
|
@@ -5422,7 +5992,8 @@
|
|
|
5422
5992
|
* @returns {Element|null} Style element if in browser, null in Node.js
|
|
5423
5993
|
* @category CSS & Styling
|
|
5424
5994
|
* @see bw.setTheme
|
|
5425
|
-
* @see bw.
|
|
5995
|
+
* @see bw.applyTheme
|
|
5996
|
+
* @see bw.toggleTheme
|
|
5426
5997
|
* @example
|
|
5427
5998
|
* bw.loadDefaultStyles(); // inject all default CSS
|
|
5428
5999
|
*/
|
|
@@ -5502,50 +6073,6 @@
|
|
|
5502
6073
|
return bw.getTheme();
|
|
5503
6074
|
};
|
|
5504
6075
|
|
|
5505
|
-
/**
|
|
5506
|
-
* Toggle dark mode on/off.
|
|
5507
|
-
*
|
|
5508
|
-
* Adds/removes the `bw-dark` class on `<html>` and injects dark mode CSS
|
|
5509
|
-
* overrides. Pass `true`/`false` to force a mode, or omit to toggle.
|
|
5510
|
-
*
|
|
5511
|
-
* @param {boolean} [force] - Force dark (true) or light (false). Omit to toggle.
|
|
5512
|
-
* @returns {boolean} Whether dark mode is now active
|
|
5513
|
-
* @category CSS & Styling
|
|
5514
|
-
* @see bw.setTheme
|
|
5515
|
-
* @example
|
|
5516
|
-
* bw.toggleDarkMode(); // toggle
|
|
5517
|
-
* bw.toggleDarkMode(true); // force dark
|
|
5518
|
-
* bw.toggleDarkMode(false); // force light
|
|
5519
|
-
*/
|
|
5520
|
-
bw.toggleDarkMode = function (force) {
|
|
5521
|
-
var isDark = force !== undefined ? force : !theme.darkMode;
|
|
5522
|
-
theme.darkMode = isDark;
|
|
5523
|
-
if (bw._isBrowser) {
|
|
5524
|
-
var root = document.documentElement;
|
|
5525
|
-
if (isDark) {
|
|
5526
|
-
root.classList.add('bw-dark');
|
|
5527
|
-
// Generate palette-aware dark mode CSS, or fall back to default
|
|
5528
|
-
var palette = bw._activePalette || derivePalette(DEFAULT_PALETTE_CONFIG);
|
|
5529
|
-
var darkRules = generateDarkModeCSS(palette);
|
|
5530
|
-
var darkCSS = bw.css(darkRules);
|
|
5531
|
-
|
|
5532
|
-
// Remove existing dark styles to allow regeneration
|
|
5533
|
-
var existing = document.getElementById('bw-dark-styles');
|
|
5534
|
-
if (existing) existing.remove();
|
|
5535
|
-
var styleEl = document.createElement('style');
|
|
5536
|
-
styleEl.id = 'bw-dark-styles';
|
|
5537
|
-
styleEl.textContent = darkCSS;
|
|
5538
|
-
document.head.appendChild(styleEl);
|
|
5539
|
-
} else {
|
|
5540
|
-
root.classList.remove('bw-dark');
|
|
5541
|
-
// Remove dark mode styles when switching to light
|
|
5542
|
-
var darkEl = document.getElementById('bw-dark-styles');
|
|
5543
|
-
if (darkEl) darkEl.remove();
|
|
5544
|
-
}
|
|
5545
|
-
}
|
|
5546
|
-
return isDark;
|
|
5547
|
-
};
|
|
5548
|
-
|
|
5549
6076
|
/**
|
|
5550
6077
|
* Generate a complete, scoped theme from seed colors.
|
|
5551
6078
|
*
|
|
@@ -5568,13 +6095,19 @@
|
|
|
5568
6095
|
* @param {string} [config.spacing='normal'] - 'compact' | 'normal' | 'spacious'
|
|
5569
6096
|
* @param {string} [config.radius='md'] - 'none' | 'sm' | 'md' | 'lg' | 'pill'
|
|
5570
6097
|
* @param {number} [config.fontSize=1.0] - Base font size scale factor
|
|
6098
|
+
* @param {string|number} [config.typeRatio='normal'] - 'tight' | 'normal' | 'relaxed' | 'dramatic' or a number
|
|
6099
|
+
* @param {string} [config.elevation='md'] - 'flat' | 'sm' | 'md' | 'lg'
|
|
6100
|
+
* @param {string} [config.motion='standard'] - 'reduced' | 'standard' | 'expressive'
|
|
6101
|
+
* @param {number} [config.harmonize=0.20] - 0-1, semantic color hue shift toward primary
|
|
5571
6102
|
* @param {boolean} [config.inject=true] - Inject into DOM (browser only)
|
|
5572
|
-
* @returns {Object} { css, palette, name }
|
|
6103
|
+
* @returns {Object} { css, palette, name, isLightPrimary, alternate: { css, palette } }
|
|
5573
6104
|
* @category CSS & Styling
|
|
6105
|
+
* @see bw.applyTheme
|
|
6106
|
+
* @see bw.toggleTheme
|
|
5574
6107
|
* @see bw.loadDefaultStyles
|
|
5575
6108
|
* @example
|
|
5576
|
-
* // Generate and inject an ocean theme
|
|
5577
|
-
* bw.generateTheme('ocean', {
|
|
6109
|
+
* // Generate and inject an ocean theme (primary + alternate)
|
|
6110
|
+
* var theme = bw.generateTheme('ocean', {
|
|
5578
6111
|
* primary: '#0077b6',
|
|
5579
6112
|
* secondary: '#90e0ef',
|
|
5580
6113
|
* tertiary: '#00b4d8'
|
|
@@ -5583,14 +6116,16 @@
|
|
|
5583
6116
|
* // Apply to a container
|
|
5584
6117
|
* document.getElementById('app').classList.add('ocean');
|
|
5585
6118
|
*
|
|
6119
|
+
* // Toggle to alternate palette
|
|
6120
|
+
* bw.toggleTheme();
|
|
6121
|
+
*
|
|
5586
6122
|
* // Generate CSS for static export (Node.js)
|
|
5587
6123
|
* var result = bw.generateTheme('sunset', {
|
|
5588
6124
|
* primary: '#e76f51',
|
|
5589
6125
|
* secondary: '#264653',
|
|
5590
|
-
* tertiary: '#e9c46a',
|
|
5591
6126
|
* inject: false
|
|
5592
6127
|
* });
|
|
5593
|
-
* fs.writeFileSync('sunset.css', result.css);
|
|
6128
|
+
* fs.writeFileSync('sunset.css', result.css + result.alternate.css);
|
|
5594
6129
|
*/
|
|
5595
6130
|
bw.generateTheme = function (name, config) {
|
|
5596
6131
|
if (!config || !config.primary || !config.secondary) {
|
|
@@ -5601,25 +6136,30 @@
|
|
|
5601
6136
|
var fullConfig = Object.assign({}, DEFAULT_PALETTE_CONFIG, config);
|
|
5602
6137
|
if (!config.tertiary) fullConfig.tertiary = fullConfig.primary;
|
|
5603
6138
|
|
|
5604
|
-
// Derive palette
|
|
6139
|
+
// Derive primary palette
|
|
5605
6140
|
var palette = derivePalette(fullConfig);
|
|
5606
6141
|
|
|
5607
|
-
// Store active palette for dark mode
|
|
5608
|
-
bw._activePalette = palette;
|
|
5609
|
-
|
|
5610
6142
|
// Resolve layout
|
|
5611
6143
|
var layout = resolveLayout(fullConfig);
|
|
5612
6144
|
|
|
5613
|
-
// Generate themed CSS rules
|
|
6145
|
+
// Generate primary themed CSS rules
|
|
5614
6146
|
var themedRules = generateThemedCSS(name, palette, layout);
|
|
5615
|
-
|
|
5616
|
-
// Add underscore aliases
|
|
5617
6147
|
var aliasedRules = addUnderscoreAliases(themedRules);
|
|
5618
|
-
|
|
5619
|
-
// Convert to CSS string
|
|
5620
6148
|
var cssStr = bw.css(aliasedRules);
|
|
5621
6149
|
|
|
5622
|
-
//
|
|
6150
|
+
// Derive alternate palette (luminance-inverted)
|
|
6151
|
+
var altConfig = deriveAlternateConfig(fullConfig);
|
|
6152
|
+
var altPalette = derivePalette(altConfig);
|
|
6153
|
+
|
|
6154
|
+
// Generate alternate CSS scoped under .bw-theme-alt
|
|
6155
|
+
var altRules = generateAlternateCSS(name, altPalette, layout);
|
|
6156
|
+
var aliasedAltRules = addUnderscoreAliases(altRules);
|
|
6157
|
+
var altCssStr = bw.css(aliasedAltRules);
|
|
6158
|
+
|
|
6159
|
+
// Determine if primary is light-flavored
|
|
6160
|
+
var lightPrimary = isLightPalette(fullConfig);
|
|
6161
|
+
|
|
6162
|
+
// Inject both CSS sets into DOM if requested
|
|
5623
6163
|
var shouldInject = config.inject !== false;
|
|
5624
6164
|
if (shouldInject && bw._isBrowser) {
|
|
5625
6165
|
var styleId = name ? 'bw-theme-' + name : 'bw-theme-default';
|
|
@@ -5627,6 +6167,11 @@
|
|
|
5627
6167
|
id: styleId,
|
|
5628
6168
|
append: false
|
|
5629
6169
|
});
|
|
6170
|
+
var altStyleId = name ? 'bw-theme-' + name + '-alt' : 'bw-theme-default-alt';
|
|
6171
|
+
bw.injectCSS(altCssStr, {
|
|
6172
|
+
id: altStyleId,
|
|
6173
|
+
append: false
|
|
6174
|
+
});
|
|
5630
6175
|
}
|
|
5631
6176
|
|
|
5632
6177
|
// Update bw.u color entries to reflect the palette
|
|
@@ -5645,11 +6190,65 @@
|
|
|
5645
6190
|
color: '#ffffff'
|
|
5646
6191
|
};
|
|
5647
6192
|
}
|
|
5648
|
-
|
|
6193
|
+
|
|
6194
|
+
// Store active theme state
|
|
6195
|
+
var result = {
|
|
5649
6196
|
css: cssStr,
|
|
5650
6197
|
palette: palette,
|
|
5651
|
-
name: name
|
|
6198
|
+
name: name,
|
|
6199
|
+
isLightPrimary: lightPrimary,
|
|
6200
|
+
alternate: {
|
|
6201
|
+
css: altCssStr,
|
|
6202
|
+
palette: altPalette
|
|
6203
|
+
}
|
|
5652
6204
|
};
|
|
6205
|
+
bw._activeTheme = result;
|
|
6206
|
+
bw._activeThemeMode = 'primary';
|
|
6207
|
+
return result;
|
|
6208
|
+
};
|
|
6209
|
+
|
|
6210
|
+
/**
|
|
6211
|
+
* Apply a theme mode. Switches between primary and alternate palettes
|
|
6212
|
+
* by adding/removing the `bw-theme-alt` class on `<html>`.
|
|
6213
|
+
*
|
|
6214
|
+
* @param {string} mode - 'primary' | 'alternate' | 'light' | 'dark'
|
|
6215
|
+
* @returns {string} Active mode: 'primary' or 'alternate'
|
|
6216
|
+
* @category CSS & Styling
|
|
6217
|
+
* @see bw.generateTheme
|
|
6218
|
+
* @see bw.toggleTheme
|
|
6219
|
+
* @example
|
|
6220
|
+
* bw.applyTheme('alternate'); // switch to alternate palette
|
|
6221
|
+
* bw.applyTheme('dark'); // switch to whichever palette is darker
|
|
6222
|
+
* bw.applyTheme('primary'); // switch back to primary palette
|
|
6223
|
+
*/
|
|
6224
|
+
bw.applyTheme = function (mode) {
|
|
6225
|
+
if (!bw._isBrowser) return mode || 'primary';
|
|
6226
|
+
var root = document.documentElement;
|
|
6227
|
+
var isLight = bw._activeTheme ? bw._activeTheme.isLightPrimary : true;
|
|
6228
|
+
var wantAlt;
|
|
6229
|
+
if (mode === 'primary') wantAlt = false;else if (mode === 'alternate') wantAlt = true;else if (mode === 'light') wantAlt = !isLight;else if (mode === 'dark') wantAlt = isLight;else wantAlt = false;
|
|
6230
|
+
if (wantAlt) {
|
|
6231
|
+
root.classList.add('bw-theme-alt');
|
|
6232
|
+
} else {
|
|
6233
|
+
root.classList.remove('bw-theme-alt');
|
|
6234
|
+
}
|
|
6235
|
+
bw._activeThemeMode = wantAlt ? 'alternate' : 'primary';
|
|
6236
|
+
return bw._activeThemeMode;
|
|
6237
|
+
};
|
|
6238
|
+
|
|
6239
|
+
/**
|
|
6240
|
+
* Toggle between primary and alternate theme palettes.
|
|
6241
|
+
*
|
|
6242
|
+
* @returns {string} Active mode after toggle: 'primary' or 'alternate'
|
|
6243
|
+
* @category CSS & Styling
|
|
6244
|
+
* @see bw.applyTheme
|
|
6245
|
+
* @see bw.generateTheme
|
|
6246
|
+
* @example
|
|
6247
|
+
* bw.toggleTheme(); // flip between primary and alternate
|
|
6248
|
+
*/
|
|
6249
|
+
bw.toggleTheme = function () {
|
|
6250
|
+
var current = bw._activeThemeMode || 'primary';
|
|
6251
|
+
return bw.applyTheme(current === 'primary' ? 'alternate' : 'primary');
|
|
5653
6252
|
};
|
|
5654
6253
|
|
|
5655
6254
|
// Expose color utility functions on bw namespace
|
|
@@ -5661,10 +6260,18 @@
|
|
|
5661
6260
|
bw.textOnColor = textOnColor;
|
|
5662
6261
|
bw.deriveShades = deriveShades;
|
|
5663
6262
|
bw.derivePalette = derivePalette;
|
|
6263
|
+
bw.harmonize = harmonize;
|
|
6264
|
+
bw.deriveAlternateSeed = deriveAlternateSeed;
|
|
6265
|
+
bw.deriveAlternateConfig = deriveAlternateConfig;
|
|
6266
|
+
bw.isLightPalette = isLightPalette;
|
|
5664
6267
|
|
|
5665
6268
|
// Expose layout and theme presets
|
|
5666
6269
|
bw.SPACING_PRESETS = SPACING_PRESETS;
|
|
5667
6270
|
bw.RADIUS_PRESETS = RADIUS_PRESETS;
|
|
6271
|
+
bw.TYPE_RATIO_PRESETS = TYPE_RATIO_PRESETS;
|
|
6272
|
+
bw.ELEVATION_PRESETS = ELEVATION_PRESETS;
|
|
6273
|
+
bw.MOTION_PRESETS = MOTION_PRESETS;
|
|
6274
|
+
bw.generateTypeScale = generateTypeScale;
|
|
5668
6275
|
bw.DEFAULT_PALETTE_CONFIG = DEFAULT_PALETTE_CONFIG;
|
|
5669
6276
|
bw.THEME_PRESETS = THEME_PRESETS;
|
|
5670
6277
|
|
|
@@ -6753,9 +7360,13 @@
|
|
|
6753
7360
|
/**
|
|
6754
7361
|
* Create a sortable TACO table from an array of row objects.
|
|
6755
7362
|
*
|
|
7363
|
+
* Returns a bare `<table>` TACO — no wrapper, title, or responsive scroll.
|
|
7364
|
+
* Use this when you need full control over table placement, or when embedding
|
|
7365
|
+
* the table inside your own layout. For a ready-to-use table with title,
|
|
7366
|
+
* responsive wrapper, and defaults (striped + hover), use `bw.makeDataTable()`.
|
|
7367
|
+
*
|
|
6756
7368
|
* Auto-detects columns from data keys if not specified. Supports click-to-sort
|
|
6757
|
-
* headers with ascending/descending indicators.
|
|
6758
|
-
* render with `bw.DOM()` or `bw.html()`.
|
|
7369
|
+
* headers with ascending/descending indicators.
|
|
6759
7370
|
*
|
|
6760
7371
|
* @param {Object} config - Table configuration
|
|
6761
7372
|
* @param {Array<Object>} config.data - Array of row objects to display
|
|
@@ -7122,10 +7733,12 @@
|
|
|
7122
7733
|
};
|
|
7123
7734
|
|
|
7124
7735
|
/**
|
|
7125
|
-
* Create a
|
|
7736
|
+
* Create a ready-to-use data table with title and responsive wrapper.
|
|
7126
7737
|
*
|
|
7127
|
-
*
|
|
7128
|
-
*
|
|
7738
|
+
* Convenience wrapper around `bw.makeTable()` that adds a title heading,
|
|
7739
|
+
* responsive horizontal scroll container, and defaults to striped + hover.
|
|
7740
|
+
* Use this for the common case; use `bw.makeTable()` when you need a bare
|
|
7741
|
+
* table element with no wrapper.
|
|
7129
7742
|
*
|
|
7130
7743
|
* @param {Object} config - Table configuration
|
|
7131
7744
|
* @param {string} [config.title] - Table title heading
|