bitwrench 2.0.18 → 2.0.20

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.
Files changed (58) hide show
  1. package/README.md +86 -81
  2. package/dist/bitwrench-bccl.cjs.js +221 -48
  3. package/dist/bitwrench-bccl.cjs.min.js +3 -3
  4. package/dist/bitwrench-bccl.esm.js +221 -48
  5. package/dist/bitwrench-bccl.esm.min.js +3 -3
  6. package/dist/bitwrench-bccl.umd.js +221 -48
  7. package/dist/bitwrench-bccl.umd.min.js +3 -3
  8. package/dist/bitwrench-code-edit.cjs.js +7 -9
  9. package/dist/bitwrench-code-edit.cjs.min.js +5 -7
  10. package/dist/bitwrench-code-edit.es5.js +6 -8
  11. package/dist/bitwrench-code-edit.es5.min.js +5 -7
  12. package/dist/bitwrench-code-edit.esm.js +7 -9
  13. package/dist/bitwrench-code-edit.esm.min.js +5 -7
  14. package/dist/bitwrench-code-edit.umd.js +7 -9
  15. package/dist/bitwrench-code-edit.umd.min.js +5 -7
  16. package/dist/bitwrench-debug.js +268 -0
  17. package/dist/bitwrench-debug.min.js +3 -0
  18. package/dist/bitwrench-lean.cjs.js +250 -1574
  19. package/dist/bitwrench-lean.cjs.min.js +6 -6
  20. package/dist/bitwrench-lean.es5.js +344 -1661
  21. package/dist/bitwrench-lean.es5.min.js +4 -4
  22. package/dist/bitwrench-lean.esm.js +250 -1574
  23. package/dist/bitwrench-lean.esm.min.js +6 -6
  24. package/dist/bitwrench-lean.umd.js +250 -1574
  25. package/dist/bitwrench-lean.umd.min.js +6 -6
  26. package/dist/bitwrench-util-css.cjs.js +1 -1
  27. package/dist/bitwrench-util-css.cjs.min.js +1 -1
  28. package/dist/bitwrench-util-css.es5.js +1 -1
  29. package/dist/bitwrench-util-css.es5.min.js +1 -1
  30. package/dist/bitwrench-util-css.esm.js +1 -1
  31. package/dist/bitwrench-util-css.esm.min.js +1 -1
  32. package/dist/bitwrench-util-css.umd.js +1 -1
  33. package/dist/bitwrench-util-css.umd.min.js +1 -1
  34. package/dist/bitwrench.cjs.js +510 -1660
  35. package/dist/bitwrench.cjs.min.js +7 -7
  36. package/dist/bitwrench.css +80 -33
  37. package/dist/bitwrench.es5.js +569 -1694
  38. package/dist/bitwrench.es5.min.js +5 -5
  39. package/dist/bitwrench.esm.js +510 -1660
  40. package/dist/bitwrench.esm.min.js +7 -7
  41. package/dist/bitwrench.min.css +1 -1
  42. package/dist/bitwrench.umd.js +510 -1660
  43. package/dist/bitwrench.umd.min.js +7 -7
  44. package/dist/builds.json +133 -111
  45. package/dist/bwserve.cjs.js +2 -2
  46. package/dist/bwserve.esm.js +2 -2
  47. package/dist/sri.json +46 -44
  48. package/package.json +5 -3
  49. package/readme.html +86 -75
  50. package/src/bitwrench-bccl-entry.js +3 -4
  51. package/src/bitwrench-bccl.js +217 -43
  52. package/src/bitwrench-code-edit.js +6 -8
  53. package/src/bitwrench-debug.js +245 -0
  54. package/src/bitwrench-styles.js +35 -8
  55. package/src/bitwrench.js +212 -1563
  56. package/src/cli/attach.js +53 -21
  57. package/src/cli/serve.js +179 -3
  58. package/src/version.js +3 -3
@@ -0,0 +1,245 @@
1
+ /**
2
+ * bitwrench-debug.js -- Standalone debug toolkit for bitwrench pages.
3
+ *
4
+ * Installs window.bwd with helper functions ported from bwcli attach:
5
+ * bwd.tree(sel, depth) -- print DOM tree to console
6
+ * bwd.listen(sel, event) -- delegated event logging
7
+ * bwd.unlisten(sel, event) -- remove event listener
8
+ * bwd.state(sel?) -- dump stateful elements via console.table
9
+ * bwd.screenshot(sel?) -- capture screenshot via html2canvas
10
+ *
11
+ * NOT bundled into bitwrench core. Load separately via script tag or
12
+ * console paste. Auto-loads bitwrench from CDN if not present.
13
+ *
14
+ * @module bitwrench-debug
15
+ */
16
+ (function() {
17
+ 'use strict';
18
+
19
+ var CDN_BW = 'https://cdn.jsdelivr.net/npm/bitwrench@2/dist/bitwrench.umd.min.js';
20
+ var CDN_H2C = 'https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js';
21
+ var _listeners = {};
22
+
23
+ function _loadScript(url) {
24
+ return new Promise(function(resolve, reject) {
25
+ var s = document.createElement('script');
26
+ s.src = url;
27
+ s.onload = function() { resolve(); };
28
+ s.onerror = function() { reject(new Error('Failed to load ' + url)); };
29
+ document.head.appendChild(s);
30
+ });
31
+ }
32
+
33
+ // -- tree -------------------------------------------------------------------
34
+
35
+ function _walk(el, depth, maxDepth) {
36
+ if (!el || depth > maxDepth) return null;
37
+ var info = { tag: el.tagName ? el.tagName.toLowerCase() : '#text' };
38
+ if (el.id) info.id = el.id;
39
+ if (el.className && typeof el.className === 'string') {
40
+ info.cls = el.className.split(' ').slice(0, 5).join(' ');
41
+ }
42
+ if (el.children && el.children.length > 0 && depth < maxDepth) {
43
+ info.children = [];
44
+ for (var i = 0; i < Math.min(el.children.length, 20); i++) {
45
+ var c = _walk(el.children[i], depth + 1, maxDepth);
46
+ if (c) info.children.push(c);
47
+ }
48
+ }
49
+ return info;
50
+ }
51
+
52
+ function _print(node, indent) {
53
+ if (!node) return;
54
+ var label = node.tag || '?';
55
+ if (node.id) label += '#' + node.id;
56
+ if (node.cls) label += '.' + node.cls.split(' ').join('.');
57
+ console.log(' '.repeat(indent) + label);
58
+ if (node.children) {
59
+ for (var i = 0; i < node.children.length; i++) {
60
+ _print(node.children[i], indent + 1);
61
+ }
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Print an indented DOM tree to the console.
67
+ * @param {string} [sel='body'] - CSS selector for the root element
68
+ * @param {number} [depth=3] - Max depth to walk
69
+ * @returns {object|null} The tree data structure
70
+ */
71
+ function tree(sel, depth) {
72
+ sel = sel || 'body';
73
+ depth = depth || 3;
74
+ var root = document.querySelector(sel);
75
+ if (!root) {
76
+ console.log('(no element found for "' + sel + '")');
77
+ return null;
78
+ }
79
+ var data = _walk(root, 0, depth);
80
+ _print(data, 0);
81
+ return data;
82
+ }
83
+
84
+ // -- listen / unlisten ------------------------------------------------------
85
+
86
+ /**
87
+ * Add a delegated event listener that logs matching events to the console.
88
+ * @param {string} sel - CSS selector to match via closest()
89
+ * @param {string} event - DOM event name (e.g. 'click')
90
+ */
91
+ function listen(sel, event) {
92
+ var key = sel + ':::' + event;
93
+ if (_listeners[key]) {
94
+ console.log('[bwd] already listening for ' + event + ' on ' + sel);
95
+ return;
96
+ }
97
+ var fn = function(e) {
98
+ var el = e.target.closest ? e.target.closest(sel) : null;
99
+ if (!el) return;
100
+ console.log('[bwd] ' + event + ' on ' + sel + ' -> ' +
101
+ el.tagName + (el.id ? '#' + el.id : '') +
102
+ (el.textContent ? ' "' + el.textContent.slice(0, 50).trim() + '"' : ''));
103
+ };
104
+ document.addEventListener(event, fn, true);
105
+ _listeners[key] = { fn: fn, event: event };
106
+ console.log('[bwd] listening for ' + event + ' on ' + sel);
107
+ }
108
+
109
+ /**
110
+ * Remove a previously added delegated event listener.
111
+ * @param {string} sel - CSS selector used in listen()
112
+ * @param {string} event - DOM event name used in listen()
113
+ */
114
+ function unlisten(sel, event) {
115
+ var key = sel + ':::' + event;
116
+ var entry = _listeners[key];
117
+ if (!entry) {
118
+ console.log('[bwd] no listener for ' + event + ' on ' + sel);
119
+ return;
120
+ }
121
+ document.removeEventListener(entry.event, entry.fn, true);
122
+ delete _listeners[key];
123
+ console.log('[bwd] stopped listening for ' + event + ' on ' + sel);
124
+ }
125
+
126
+ // -- state ------------------------------------------------------------------
127
+
128
+ /**
129
+ * Dump all stateful (.bw_lc) elements and their _bw_state via console.table.
130
+ * @param {string} [sel='.bw_lc'] - CSS selector to query
131
+ * @returns {Array} Array of {id, uuid, state} objects
132
+ */
133
+ function state(sel) {
134
+ sel = sel || '.bw_lc';
135
+ var els = document.querySelectorAll(sel);
136
+ var rows = [];
137
+ for (var i = 0; i < els.length; i++) {
138
+ var el = els[i];
139
+ var uuid = '';
140
+ if (typeof window !== 'undefined' && window.bw && window.bw.getUUID) {
141
+ uuid = window.bw.getUUID(el) || '';
142
+ }
143
+ rows.push({
144
+ id: el.id || '',
145
+ uuid: uuid,
146
+ state: el._bw_state || null
147
+ });
148
+ }
149
+ if (rows.length === 0) {
150
+ console.log('[bwd] no stateful elements found for "' + sel + '"');
151
+ } else if (typeof console.table === 'function') {
152
+ console.table(rows);
153
+ } else {
154
+ console.log(rows);
155
+ }
156
+ return rows;
157
+ }
158
+
159
+ // -- screenshot -------------------------------------------------------------
160
+
161
+ /**
162
+ * Capture a screenshot via html2canvas and trigger a download.
163
+ * Loads html2canvas from CDN if not present.
164
+ * @param {string} [sel='body'] - CSS selector for the element to capture
165
+ * @returns {Promise} Resolves when screenshot is saved
166
+ */
167
+ function screenshot(sel) {
168
+ sel = sel || 'body';
169
+ var el = document.querySelector(sel);
170
+ if (!el) {
171
+ console.log('[bwd] no element found for "' + sel + '"');
172
+ return Promise.resolve(null);
173
+ }
174
+
175
+ var p = (typeof window !== 'undefined' && window.html2canvas)
176
+ ? Promise.resolve(window.html2canvas)
177
+ : _loadScript(CDN_H2C).then(function() { return window.html2canvas; });
178
+
179
+ return p.then(function(h2c) {
180
+ console.log('[bwd] capturing ' + sel + ' ...');
181
+ return h2c(el, { useCORS: true });
182
+ }).then(function(canvas) {
183
+ var filename = 'screenshot-' + Date.now() + '.png';
184
+ canvas.toBlob(function(blob) {
185
+ if (typeof window !== 'undefined' && window.bw && window.bw.saveClientFile) {
186
+ window.bw.saveClientFile(filename, blob);
187
+ } else {
188
+ // Fallback: create a download link
189
+ var a = document.createElement('a');
190
+ a.href = URL.createObjectURL(blob);
191
+ a.download = filename;
192
+ a.click();
193
+ URL.revokeObjectURL(a.href);
194
+ }
195
+ console.log('[bwd] saved: ' + filename);
196
+ });
197
+ }).catch(function(err) {
198
+ console.error('[bwd] screenshot failed: ' + err.message);
199
+ });
200
+ }
201
+
202
+ // -- init -------------------------------------------------------------------
203
+
204
+ var bwd = {
205
+ tree: tree,
206
+ listen: listen,
207
+ unlisten: unlisten,
208
+ state: state,
209
+ screenshot: screenshot,
210
+ _listeners: _listeners
211
+ };
212
+
213
+ // Expose for testing in Node (module.exports) or browser (window.bwd)
214
+ if (typeof module !== 'undefined' && module.exports) {
215
+ module.exports = bwd;
216
+ }
217
+ if (typeof window !== 'undefined') {
218
+ window.bwd = bwd;
219
+ }
220
+
221
+ function _printReady() {
222
+ console.log('[bwd] bitwrench debug toolkit ready');
223
+ console.log(' bwd.tree(sel?, depth?) -- print DOM tree');
224
+ console.log(' bwd.listen(sel, event) -- log events');
225
+ console.log(' bwd.unlisten(sel, event) -- stop logging');
226
+ console.log(' bwd.state(sel?) -- dump stateful elements');
227
+ console.log(' bwd.screenshot(sel?) -- capture screenshot');
228
+ }
229
+
230
+ // Auto-load bitwrench from CDN if not present
231
+ if (typeof window !== 'undefined') {
232
+ if (window.bw && window.bw.version) {
233
+ _printReady();
234
+ } else {
235
+ console.log('[bwd] bitwrench not detected, loading from CDN...');
236
+ _loadScript(CDN_BW).then(function() {
237
+ _printReady();
238
+ }).catch(function(err) {
239
+ console.warn('[bwd] could not load bitwrench: ' + err.message);
240
+ console.log('[bwd] toolkit ready (limited -- bw.* not available)');
241
+ console.log(' bwd.tree, bwd.listen, bwd.unlisten still work');
242
+ });
243
+ }
244
+ }
245
+ })();
@@ -1703,10 +1703,10 @@ var structuralRules = {
1703
1703
  'position': 'relative', 'display': 'flex', 'flex-direction': 'column', 'pointer-events': 'auto',
1704
1704
  'background-clip': 'padding-box', 'border': '1px solid transparent', 'outline': '0'
1705
1705
  },
1706
- '.bw_modal_header': { 'display': 'flex', 'align-items': 'center', 'justify-content': 'space-between' },
1706
+ '.bw_modal_header': { 'display': 'flex', 'align-items': 'center', 'justify-content': 'space-between', 'padding': '1rem 1.25rem', 'border-bottom': '1px solid transparent' },
1707
1707
  '.bw_modal_title': { 'margin': '0', 'font-size': '1.25rem', 'font-weight': '600', 'line-height': '1.3' },
1708
- '.bw_modal_body': { 'position': 'relative', 'flex': '1 1 auto' },
1709
- '.bw_modal_footer': { 'display': 'flex', 'flex-wrap': 'wrap', 'align-items': 'center', 'justify-content': 'flex-end', 'gap': '0.5rem' }
1708
+ '.bw_modal_body': { 'position': 'relative', 'flex': '1 1 auto', 'padding': '1rem 1.25rem' },
1709
+ '.bw_modal_footer': { 'display': 'flex', 'flex-wrap': 'wrap', 'align-items': 'center', 'justify-content': 'flex-end', 'gap': '0.5rem', 'padding': '0.75rem 1.25rem', 'border-top': '1px solid transparent' }
1710
1710
  },
1711
1711
 
1712
1712
  // ---- Toast ----
@@ -1727,8 +1727,8 @@ var structuralRules = {
1727
1727
  },
1728
1728
  '.bw_toast.bw_toast_show': { 'opacity': '1', 'transform': 'translateY(0)' },
1729
1729
  '.bw_toast.bw_toast_hiding': { 'opacity': '0' },
1730
- '.bw_toast_header': { 'display': 'flex', 'align-items': 'center', 'justify-content': 'space-between', 'font-size': '0.875rem' },
1731
- '.bw_toast_body': { 'font-size': '0.9375rem' }
1730
+ '.bw_toast_header': { 'display': 'flex', 'align-items': 'center', 'justify-content': 'space-between', 'padding': '0.5rem 0.75rem', 'font-size': '0.875rem', 'border-bottom': '1px solid transparent' },
1731
+ '.bw_toast_body': { 'padding': '0.5rem 0.75rem', 'font-size': '0.9375rem' }
1732
1732
  },
1733
1733
 
1734
1734
  // ---- Dropdown ----
@@ -1742,15 +1742,15 @@ var structuralRules = {
1742
1742
  '.bw_dropdown_menu': {
1743
1743
  'position': 'absolute', 'top': '100%', 'left': '0', 'z-index': '1000', 'display': 'block',
1744
1744
  'min-width': '10rem', 'padding': '0.5rem 0', 'margin': '0.125rem 0 0',
1745
- 'background-clip': 'padding-box',
1745
+ 'background-clip': 'padding-box', 'border': '1px solid transparent',
1746
1746
  'opacity': '0', 'visibility': 'hidden', 'pointer-events': 'none'
1747
1747
  },
1748
1748
  '.bw_dropdown_menu.bw_dropdown_show': { 'opacity': '1', 'visibility': 'visible', 'pointer-events': 'auto' },
1749
1749
  '.bw_dropdown_menu_end': { 'left': 'auto', 'right': '0' },
1750
1750
  '.bw_dropdown_item': {
1751
- 'display': 'block', 'width': '100%', 'clear': 'both',
1751
+ 'display': 'block', 'width': '100%', 'padding': '0.4rem 1rem', 'clear': 'both',
1752
1752
  'font-weight': '400', 'text-align': 'inherit', 'text-decoration': 'none', 'white-space': 'nowrap',
1753
- 'background-color': 'transparent', 'border': '0', 'font-size': '0.9375rem'
1753
+ 'background-color': 'transparent', 'border': '0', 'font-size': '0.9375rem', 'cursor': 'pointer'
1754
1754
  },
1755
1755
  '.bw_dropdown_item:focus-visible': { 'outline': '2px solid currentColor', 'outline-offset': '-2px' },
1756
1756
  '.bw_dropdown_divider': { 'height': '0', 'margin': '0.5rem 0', 'overflow': 'hidden', 'opacity': '1' }
@@ -2072,6 +2072,33 @@ function generateUtilityRules() {
2072
2072
  rules['.bw_text_left'] = { 'text-align': 'left' };
2073
2073
  rules['.bw_text_right'] = { 'text-align': 'right' };
2074
2074
  rules['.bw_text_center'] = { 'text-align': 'center' };
2075
+ rules['.bw_text_justify'] = { 'text-align': 'justify' };
2076
+
2077
+ // Font weight
2078
+ rules['.bw_fw_bold'] = { 'font-weight': '700' };
2079
+ rules['.bw_fw_semibold'] = { 'font-weight': '600' };
2080
+ rules['.bw_fw_normal'] = { 'font-weight': '400' };
2081
+ rules['.bw_fw_light'] = { 'font-weight': '300' };
2082
+
2083
+ // Font style
2084
+ rules['.bw_fst_italic'] = { 'font-style': 'italic' };
2085
+ rules['.bw_fst_normal'] = { 'font-style': 'normal' };
2086
+
2087
+ // Text decoration
2088
+ rules['.bw_text_underline'] = { 'text-decoration': 'underline' };
2089
+ rules['.bw_text_line_through'] = { 'text-decoration': 'line-through' };
2090
+ rules['.bw_text_decoration_none'] = { 'text-decoration': 'none' };
2091
+
2092
+ // Text transform
2093
+ rules['.bw_text_uppercase'] = { 'text-transform': 'uppercase' };
2094
+ rules['.bw_text_lowercase'] = { 'text-transform': 'lowercase' };
2095
+ rules['.bw_text_capitalize'] = { 'text-transform': 'capitalize' };
2096
+
2097
+ // Font size
2098
+ rules['.bw_fs_sm'] = { 'font-size': '0.875rem' };
2099
+ rules['.bw_fs_base'] = { 'font-size': '1rem' };
2100
+ rules['.bw_fs_lg'] = { 'font-size': '1.25rem' };
2101
+ rules['.bw_fs_xl'] = { 'font-size': '1.5rem' };
2075
2102
 
2076
2103
  // Flexbox
2077
2104
  var jc = { start: 'flex-start', end: 'flex-end', center: 'center', between: 'space-between', around: 'space-around' };