bitwrench 2.0.13 → 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/src/bitwrench.js CHANGED
@@ -8,13 +8,15 @@
8
8
  */
9
9
 
10
10
  import { VERSION_INFO } from './version.js';
11
- import { getStructuralStyles, theme, updateTheme, generateDarkModeCSS,
12
- generateThemedCSS, derivePalette as _derivePalette,
11
+ import { getStructuralStyles, theme, updateTheme,
12
+ generateThemedCSS, generateAlternateCSS, derivePalette as _derivePalette,
13
13
  DEFAULT_PALETTE_CONFIG, SPACING_PRESETS, RADIUS_PRESETS, THEME_PRESETS,
14
+ TYPE_RATIO_PRESETS, ELEVATION_PRESETS, MOTION_PRESETS, generateTypeScale,
14
15
  resolveLayout, addUnderscoreAliases } from './bitwrench-styles.js';
15
16
  import { hexToHsl, hslToHex, adjustLightness, mixColor,
16
17
  relativeLuminance, textOnColor, deriveShades,
17
- derivePalette } from './bitwrench-color-utils.js';
18
+ derivePalette, harmonize, deriveAlternateSeed, deriveAlternateConfig,
19
+ isLightPalette } from './bitwrench-color-utils.js';
18
20
 
19
21
  // Environment-aware module loader for optional Node.js built-ins (fs).
20
22
  // Strategy: try require() first (CJS/UMD), fall back to import() (ESM).
@@ -1624,8 +1626,10 @@ bw.u = {
1624
1626
  /**
1625
1627
  * Generate responsive CSS with media query breakpoints.
1626
1628
  *
1627
- * Produces a CSS string with `@media` rules for sm (640px), md (768px),
1628
- * lg (1024px), and xl (1280px) breakpoints. Pass the result to `bw.injectCSS()`.
1629
+ * Produces a CSS string with `@media (min-width)` rules for standard
1630
+ * breakpoints. These match the grid system and theme.breakpoints:
1631
+ * sm: 576px, md: 768px, lg: 992px, xl: 1200px
1632
+ * Pass the result to `bw.injectCSS()`.
1629
1633
  *
1630
1634
  * @param {string} selector - CSS selector
1631
1635
  * @param {Object} breakpoints - Object with keys: base, sm, md, lg, xl
@@ -1642,7 +1646,7 @@ bw.u = {
1642
1646
  * bw.injectCSS(css);
1643
1647
  */
1644
1648
  bw.responsive = function(selector, breakpoints) {
1645
- var sizes = { sm: '640px', md: '768px', lg: '1024px', xl: '1280px' };
1649
+ var sizes = { sm: '576px', md: '768px', lg: '992px', xl: '1200px' };
1646
1650
  var parts = [];
1647
1651
  Object.keys(breakpoints).forEach(function(key) {
1648
1652
  var rules = {};
@@ -1776,7 +1780,8 @@ if (bw._isBrowser) {
1776
1780
  * @returns {Element|null} Style element if in browser, null in Node.js
1777
1781
  * @category CSS & Styling
1778
1782
  * @see bw.setTheme
1779
- * @see bw.toggleDarkMode
1783
+ * @see bw.applyTheme
1784
+ * @see bw.toggleTheme
1780
1785
  * @example
1781
1786
  * bw.loadDefaultStyles(); // inject all default CSS
1782
1787
  */
@@ -1843,53 +1848,6 @@ bw.setTheme = function(overrides, options = {}) {
1843
1848
  return bw.getTheme();
1844
1849
  };
1845
1850
 
1846
- /**
1847
- * Toggle dark mode on/off.
1848
- *
1849
- * Adds/removes the `bw-dark` class on `<html>` and injects dark mode CSS
1850
- * overrides. Pass `true`/`false` to force a mode, or omit to toggle.
1851
- *
1852
- * @param {boolean} [force] - Force dark (true) or light (false). Omit to toggle.
1853
- * @returns {boolean} Whether dark mode is now active
1854
- * @category CSS & Styling
1855
- * @see bw.setTheme
1856
- * @example
1857
- * bw.toggleDarkMode(); // toggle
1858
- * bw.toggleDarkMode(true); // force dark
1859
- * bw.toggleDarkMode(false); // force light
1860
- */
1861
- bw.toggleDarkMode = function(force) {
1862
- const isDark = force !== undefined ? force : !theme.darkMode;
1863
- theme.darkMode = isDark;
1864
-
1865
- if (bw._isBrowser) {
1866
- const root = document.documentElement;
1867
- if (isDark) {
1868
- root.classList.add('bw-dark');
1869
- // Generate palette-aware dark mode CSS, or fall back to default
1870
- var palette = bw._activePalette || derivePalette(DEFAULT_PALETTE_CONFIG);
1871
- var darkRules = generateDarkModeCSS(palette);
1872
- var darkCSS = bw.css(darkRules);
1873
-
1874
- // Remove existing dark styles to allow regeneration
1875
- var existing = document.getElementById('bw-dark-styles');
1876
- if (existing) existing.remove();
1877
-
1878
- var styleEl = document.createElement('style');
1879
- styleEl.id = 'bw-dark-styles';
1880
- styleEl.textContent = darkCSS;
1881
- document.head.appendChild(styleEl);
1882
- } else {
1883
- root.classList.remove('bw-dark');
1884
- // Remove dark mode styles when switching to light
1885
- var darkEl = document.getElementById('bw-dark-styles');
1886
- if (darkEl) darkEl.remove();
1887
- }
1888
- }
1889
-
1890
- return isDark;
1891
- };
1892
-
1893
1851
  /**
1894
1852
  * Generate a complete, scoped theme from seed colors.
1895
1853
  *
@@ -1912,13 +1870,19 @@ bw.toggleDarkMode = function(force) {
1912
1870
  * @param {string} [config.spacing='normal'] - 'compact' | 'normal' | 'spacious'
1913
1871
  * @param {string} [config.radius='md'] - 'none' | 'sm' | 'md' | 'lg' | 'pill'
1914
1872
  * @param {number} [config.fontSize=1.0] - Base font size scale factor
1873
+ * @param {string|number} [config.typeRatio='normal'] - 'tight' | 'normal' | 'relaxed' | 'dramatic' or a number
1874
+ * @param {string} [config.elevation='md'] - 'flat' | 'sm' | 'md' | 'lg'
1875
+ * @param {string} [config.motion='standard'] - 'reduced' | 'standard' | 'expressive'
1876
+ * @param {number} [config.harmonize=0.20] - 0-1, semantic color hue shift toward primary
1915
1877
  * @param {boolean} [config.inject=true] - Inject into DOM (browser only)
1916
- * @returns {Object} { css, palette, name }
1878
+ * @returns {Object} { css, palette, name, isLightPrimary, alternate: { css, palette } }
1917
1879
  * @category CSS & Styling
1880
+ * @see bw.applyTheme
1881
+ * @see bw.toggleTheme
1918
1882
  * @see bw.loadDefaultStyles
1919
1883
  * @example
1920
- * // Generate and inject an ocean theme
1921
- * bw.generateTheme('ocean', {
1884
+ * // Generate and inject an ocean theme (primary + alternate)
1885
+ * var theme = bw.generateTheme('ocean', {
1922
1886
  * primary: '#0077b6',
1923
1887
  * secondary: '#90e0ef',
1924
1888
  * tertiary: '#00b4d8'
@@ -1927,14 +1891,16 @@ bw.toggleDarkMode = function(force) {
1927
1891
  * // Apply to a container
1928
1892
  * document.getElementById('app').classList.add('ocean');
1929
1893
  *
1894
+ * // Toggle to alternate palette
1895
+ * bw.toggleTheme();
1896
+ *
1930
1897
  * // Generate CSS for static export (Node.js)
1931
1898
  * var result = bw.generateTheme('sunset', {
1932
1899
  * primary: '#e76f51',
1933
1900
  * secondary: '#264653',
1934
- * tertiary: '#e9c46a',
1935
1901
  * inject: false
1936
1902
  * });
1937
- * fs.writeFileSync('sunset.css', result.css);
1903
+ * fs.writeFileSync('sunset.css', result.css + result.alternate.css);
1938
1904
  */
1939
1905
  bw.generateTheme = function(name, config) {
1940
1906
  if (!config || !config.primary || !config.secondary) {
@@ -1945,29 +1911,37 @@ bw.generateTheme = function(name, config) {
1945
1911
  var fullConfig = Object.assign({}, DEFAULT_PALETTE_CONFIG, config);
1946
1912
  if (!config.tertiary) fullConfig.tertiary = fullConfig.primary;
1947
1913
 
1948
- // Derive palette
1914
+ // Derive primary palette
1949
1915
  var palette = derivePalette(fullConfig);
1950
1916
 
1951
- // Store active palette for dark mode
1952
- bw._activePalette = palette;
1953
-
1954
1917
  // Resolve layout
1955
1918
  var layout = resolveLayout(fullConfig);
1956
1919
 
1957
- // Generate themed CSS rules
1920
+ // Generate primary themed CSS rules
1958
1921
  var themedRules = generateThemedCSS(name, palette, layout);
1959
-
1960
- // Add underscore aliases
1961
1922
  var aliasedRules = addUnderscoreAliases(themedRules);
1962
-
1963
- // Convert to CSS string
1964
1923
  var cssStr = bw.css(aliasedRules);
1965
1924
 
1966
- // Inject into DOM if requested and in browser
1925
+ // Derive alternate palette (luminance-inverted)
1926
+ var altConfig = deriveAlternateConfig(fullConfig);
1927
+ var altPalette = derivePalette(altConfig);
1928
+
1929
+ // Generate alternate CSS scoped under .bw-theme-alt
1930
+ var altRules = generateAlternateCSS(name, altPalette, layout);
1931
+ var aliasedAltRules = addUnderscoreAliases(altRules);
1932
+ var altCssStr = bw.css(aliasedAltRules);
1933
+
1934
+ // Determine if primary is light-flavored
1935
+ var lightPrimary = isLightPalette(fullConfig);
1936
+
1937
+ // Inject both CSS sets into DOM if requested
1967
1938
  var shouldInject = config.inject !== false;
1968
1939
  if (shouldInject && bw._isBrowser) {
1969
1940
  var styleId = name ? 'bw-theme-' + name : 'bw-theme-default';
1970
1941
  bw.injectCSS(cssStr, { id: styleId, append: false });
1942
+
1943
+ var altStyleId = name ? 'bw-theme-' + name + '-alt' : 'bw-theme-default-alt';
1944
+ bw.injectCSS(altCssStr, { id: altStyleId, append: false });
1971
1945
  }
1972
1946
 
1973
1947
  // Update bw.u color entries to reflect the palette
@@ -1978,7 +1952,72 @@ bw.generateTheme = function(name, config) {
1978
1952
  bw.u.textWhite = { color: '#ffffff' };
1979
1953
  }
1980
1954
 
1981
- return { css: cssStr, palette: palette, name: name };
1955
+ // Store active theme state
1956
+ var result = {
1957
+ css: cssStr,
1958
+ palette: palette,
1959
+ name: name,
1960
+ isLightPrimary: lightPrimary,
1961
+ alternate: {
1962
+ css: altCssStr,
1963
+ palette: altPalette
1964
+ }
1965
+ };
1966
+ bw._activeTheme = result;
1967
+ bw._activeThemeMode = 'primary';
1968
+
1969
+ return result;
1970
+ };
1971
+
1972
+ /**
1973
+ * Apply a theme mode. Switches between primary and alternate palettes
1974
+ * by adding/removing the `bw-theme-alt` class on `<html>`.
1975
+ *
1976
+ * @param {string} mode - 'primary' | 'alternate' | 'light' | 'dark'
1977
+ * @returns {string} Active mode: 'primary' or 'alternate'
1978
+ * @category CSS & Styling
1979
+ * @see bw.generateTheme
1980
+ * @see bw.toggleTheme
1981
+ * @example
1982
+ * bw.applyTheme('alternate'); // switch to alternate palette
1983
+ * bw.applyTheme('dark'); // switch to whichever palette is darker
1984
+ * bw.applyTheme('primary'); // switch back to primary palette
1985
+ */
1986
+ bw.applyTheme = function(mode) {
1987
+ if (!bw._isBrowser) return mode || 'primary';
1988
+ var root = document.documentElement;
1989
+ var isLight = bw._activeTheme ? bw._activeTheme.isLightPrimary : true;
1990
+
1991
+ var wantAlt;
1992
+ if (mode === 'primary') wantAlt = false;
1993
+ else if (mode === 'alternate') wantAlt = true;
1994
+ else if (mode === 'light') wantAlt = !isLight;
1995
+ else if (mode === 'dark') wantAlt = isLight;
1996
+ else wantAlt = false;
1997
+
1998
+ if (wantAlt) {
1999
+ root.classList.add('bw-theme-alt');
2000
+ } else {
2001
+ root.classList.remove('bw-theme-alt');
2002
+ }
2003
+
2004
+ bw._activeThemeMode = wantAlt ? 'alternate' : 'primary';
2005
+ return bw._activeThemeMode;
2006
+ };
2007
+
2008
+ /**
2009
+ * Toggle between primary and alternate theme palettes.
2010
+ *
2011
+ * @returns {string} Active mode after toggle: 'primary' or 'alternate'
2012
+ * @category CSS & Styling
2013
+ * @see bw.applyTheme
2014
+ * @see bw.generateTheme
2015
+ * @example
2016
+ * bw.toggleTheme(); // flip between primary and alternate
2017
+ */
2018
+ bw.toggleTheme = function() {
2019
+ var current = bw._activeThemeMode || 'primary';
2020
+ return bw.applyTheme(current === 'primary' ? 'alternate' : 'primary');
1982
2021
  };
1983
2022
 
1984
2023
  // Expose color utility functions on bw namespace
@@ -1990,10 +2029,18 @@ bw.relativeLuminance = relativeLuminance;
1990
2029
  bw.textOnColor = textOnColor;
1991
2030
  bw.deriveShades = deriveShades;
1992
2031
  bw.derivePalette = derivePalette;
2032
+ bw.harmonize = harmonize;
2033
+ bw.deriveAlternateSeed = deriveAlternateSeed;
2034
+ bw.deriveAlternateConfig = deriveAlternateConfig;
2035
+ bw.isLightPalette = isLightPalette;
1993
2036
 
1994
2037
  // Expose layout and theme presets
1995
2038
  bw.SPACING_PRESETS = SPACING_PRESETS;
1996
2039
  bw.RADIUS_PRESETS = RADIUS_PRESETS;
2040
+ bw.TYPE_RATIO_PRESETS = TYPE_RATIO_PRESETS;
2041
+ bw.ELEVATION_PRESETS = ELEVATION_PRESETS;
2042
+ bw.MOTION_PRESETS = MOTION_PRESETS;
2043
+ bw.generateTypeScale = generateTypeScale;
1997
2044
  bw.DEFAULT_PALETTE_CONFIG = DEFAULT_PALETTE_CONFIG;
1998
2045
  bw.THEME_PRESETS = THEME_PRESETS;
1999
2046
 
@@ -3035,9 +3082,13 @@ bw.copyToClipboard = function(text) {
3035
3082
  /**
3036
3083
  * Create a sortable TACO table from an array of row objects.
3037
3084
  *
3085
+ * Returns a bare `<table>` TACO — no wrapper, title, or responsive scroll.
3086
+ * Use this when you need full control over table placement, or when embedding
3087
+ * the table inside your own layout. For a ready-to-use table with title,
3088
+ * responsive wrapper, and defaults (striped + hover), use `bw.makeDataTable()`.
3089
+ *
3038
3090
  * Auto-detects columns from data keys if not specified. Supports click-to-sort
3039
- * headers with ascending/descending indicators. Returns a TACO object —
3040
- * render with `bw.DOM()` or `bw.html()`.
3091
+ * headers with ascending/descending indicators.
3041
3092
  *
3042
3093
  * @param {Object} config - Table configuration
3043
3094
  * @param {Array<Object>} config.data - Array of row objects to display
@@ -3337,10 +3388,12 @@ bw.makeBarChart = function(config) {
3337
3388
  };
3338
3389
 
3339
3390
  /**
3340
- * Create a responsive data table with title and optional wrapper
3391
+ * Create a ready-to-use data table with title and responsive wrapper.
3341
3392
  *
3342
- * Wraps bw.makeTable() output in a responsive container div.
3343
- * Adds an optional title heading above the table.
3393
+ * Convenience wrapper around `bw.makeTable()` that adds a title heading,
3394
+ * responsive horizontal scroll container, and defaults to striped + hover.
3395
+ * Use this for the common case; use `bw.makeTable()` when you need a bare
3396
+ * table element with no wrapper.
3344
3397
  *
3345
3398
  * @param {Object} config - Table configuration
3346
3399
  * @param {string} [config.title] - Table title heading
package/src/version.js CHANGED
@@ -3,14 +3,14 @@
3
3
  * DO NOT EDIT DIRECTLY - Use npm run generate-version
4
4
  */
5
5
 
6
- export const VERSION = '2.0.13';
6
+ export const VERSION = '2.0.14';
7
7
  export const VERSION_INFO = {
8
- version: '2.0.13',
8
+ version: '2.0.14',
9
9
  name: 'bitwrench',
10
10
  description: 'A library for javascript UI functions.',
11
11
  license: 'BSD-2-Clause',
12
12
  homepage: 'https://deftio.github.com/bitwrench/pages',
13
13
  repository: 'git+https://github.com/deftio/bitwrench.git',
14
14
  author: 'manu a. chatterjee <deftio@deftio.com> (https://deftio.com/)',
15
- buildDate: '2026-03-07T22:35:06.056Z'
15
+ buildDate: '2026-03-08T08:04:06.572Z'
16
16
  };