bitwrench 1.2.16 → 2.0.7

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 (130) hide show
  1. package/README.md +160 -158
  2. package/bin/bitwrench.js +3 -0
  3. package/dist/bitwrench-code-edit.cjs.js +639 -0
  4. package/dist/bitwrench-code-edit.es5.js +875 -0
  5. package/dist/bitwrench-code-edit.es5.min.js +15 -0
  6. package/dist/bitwrench-code-edit.esm.js +628 -0
  7. package/dist/bitwrench-code-edit.esm.min.js +15 -0
  8. package/dist/bitwrench-code-edit.umd.js +645 -0
  9. package/dist/bitwrench-code-edit.umd.min.js +15 -0
  10. package/dist/bitwrench.cjs.js +6983 -0
  11. package/dist/bitwrench.cjs.min.js +62 -0
  12. package/dist/bitwrench.css +5100 -0
  13. package/dist/bitwrench.es5.js +8446 -0
  14. package/dist/bitwrench.es5.min.js +31 -0
  15. package/dist/bitwrench.esm.js +6981 -0
  16. package/dist/bitwrench.esm.min.js +62 -0
  17. package/dist/bitwrench.umd.js +6989 -0
  18. package/dist/bitwrench.umd.min.js +62 -0
  19. package/dist/builds.json +127 -0
  20. package/dist/sri.json +18 -0
  21. package/package.json +86 -24
  22. package/readme.html +288 -0
  23. package/src/bitwrench-code-edit.js +627 -0
  24. package/src/bitwrench-color-utils.js +311 -0
  25. package/src/bitwrench-component-base.js +736 -0
  26. package/src/bitwrench-components-inline.js +374 -0
  27. package/src/bitwrench-components-v2.js +1879 -0
  28. package/src/bitwrench-components.js +610 -0
  29. package/src/bitwrench-styles.js +3240 -0
  30. package/src/bitwrench.js +3367 -0
  31. package/src/cli/convert.js +205 -0
  32. package/src/cli/index.js +122 -0
  33. package/src/cli/inject.js +55 -0
  34. package/src/cli/layout-default.js +142 -0
  35. package/src/generate-css.js +381 -0
  36. package/src/vendor/quikdown.js +654 -0
  37. package/src/version.js +16 -0
  38. package/.eslintrc.json +0 -27
  39. package/.github/workflows/codeql-analysis.yml +0 -72
  40. package/.travis.yml +0 -34
  41. package/bitwrench.css +0 -92
  42. package/bitwrench.js +0 -3348
  43. package/bitwrench.js_sri.txt +0 -1
  44. package/bitwrench.min.js +0 -1
  45. package/bitwrench.min.js_sri.txt +0 -1
  46. package/bitwrench_ESM.js +0 -3207
  47. package/bitwrench_ESM.js_sri.txt +0 -1
  48. package/bitwrench_ESM.min.js +0 -1
  49. package/bitwrench_ESM.min.js_sri.txt +0 -1
  50. package/dev/bitwrench-todo.md +0 -215
  51. package/dev/css-arrows.md +0 -23
  52. package/dev/docStringDev.js +0 -124
  53. package/dev/docStringParseDev.js +0 -171
  54. package/dev/example11-load-mjs-page.html +0 -17
  55. package/dev/figures.html +0 -37
  56. package/dev/html_gen.js +0 -349
  57. package/dev/htmld.md +0 -250
  58. package/dev/htmldev.html +0 -45
  59. package/dev/index-old.html +0 -87
  60. package/dev/misc-notes.md +0 -21
  61. package/dev/norm.css +0 -30
  62. package/dev/notes.md +0 -2
  63. package/dev/pageData.mjs +0 -69
  64. package/dev/sizes.html +0 -49
  65. package/dev/universal-js-module.js +0 -37
  66. package/examples/example1.html +0 -78
  67. package/examples/example10.html +0 -84
  68. package/examples/example11.html +0 -17
  69. package/examples/example12.html +0 -18
  70. package/examples/example2.html +0 -44
  71. package/examples/example3.html +0 -50
  72. package/examples/example4.html +0 -22
  73. package/examples/example5.html +0 -82
  74. package/examples/example6.html +0 -128
  75. package/examples/example7.html +0 -91
  76. package/examples/example8.html +0 -27
  77. package/examples/example9.html +0 -102
  78. package/examples/examplePageData12.mjs +0 -73
  79. package/examples/pageData.mjs +0 -69
  80. package/examples/pico.min.css +0 -5
  81. package/icon/bitwrench-dark-tall.png +0 -0
  82. package/icon/bitwrench-dark.png +0 -0
  83. package/icon/bitwrench-icon-lt-grey.png +0 -0
  84. package/icon/bitwrench-icon.vsd +0 -0
  85. package/icon/bitwrench-logo-dark.png +0 -0
  86. package/icon/bitwrench-logo-full.png +0 -0
  87. package/icon/bitwrench-logo-green.png +0 -0
  88. package/icon/bitwrench-logo-grey.png +0 -0
  89. package/icon/bitwrench-logo-white.png +0 -0
  90. package/icon/bitwrench-logos-colors.png +0 -0
  91. package/icon/bitwrench-thick-logo.png +0 -0
  92. package/icon/bitwrench-thick-teal/android-chrome-192x192.png +0 -0
  93. package/icon/bitwrench-thick-teal/android-chrome-512x512.png +0 -0
  94. package/icon/bitwrench-thick-teal/apple-touch-icon.png +0 -0
  95. package/icon/bitwrench-thick-teal/browserconfig.xml +0 -9
  96. package/icon/bitwrench-thick-teal/favicon-16x16.png +0 -0
  97. package/icon/bitwrench-thick-teal/favicon-32x32.png +0 -0
  98. package/icon/bitwrench-thick-teal/favicon.ico +0 -0
  99. package/icon/bitwrench-thick-teal/mstile-144x144.png +0 -0
  100. package/icon/bitwrench-thick-teal/mstile-150x150.png +0 -0
  101. package/icon/bitwrench-thick-teal/mstile-310x150.png +0 -0
  102. package/icon/bitwrench-thick-teal/mstile-310x310.png +0 -0
  103. package/icon/bitwrench-thick-teal/mstile-70x70.png +0 -0
  104. package/icon/bitwrench-thick-teal/site.webmanifest +0 -19
  105. package/icon/bitwrench-thick-teal.ico +0 -0
  106. package/icon/bitwrench-thick-teal.svg +0 -44
  107. package/icon/bitwrench-thick-teal.zip +0 -0
  108. package/icon/favicon-test.html +0 -20
  109. package/icon/logos-test.PNG +0 -0
  110. package/images/bitwrench-512x512.png +0 -0
  111. package/images/bitwrench-logo-med.png +0 -0
  112. package/images/bitwrench-thick-logo.png +0 -0
  113. package/images/bitwrench-thick-logo.svg +0 -64
  114. package/images/bitwrench-thick-teal.ico +0 -0
  115. package/images/favicon.ico +0 -0
  116. package/index.html +0 -282
  117. package/instr_tmp/bitwrench.js +0 -1350
  118. package/karma.conf.js +0 -140
  119. package/makefile +0 -21
  120. package/quick-docs.html +0 -206
  121. package/test/bitwrench_test.js +0 -1255
  122. package/test/karma-test.js +0 -1081
  123. package/tools/bw_deprecatedNames.js +0 -19
  124. package/tools/bwconsole.js +0 -20
  125. package/tools/createSimpleHTMLPage.js +0 -41
  126. package/tools/emitreadme.sh +0 -4
  127. package/tools/export-bw-default-css.js +0 -41
  128. package/tools/umd2ModuleHack.js +0 -32
  129. package/tools/update-bw-package.js +0 -36
  130. package/tools/updatereadme.js +0 -34
@@ -0,0 +1,875 @@
1
+ /*! bitwrench v2.0.7 | BSD-2-Clause | http://deftio.com/bitwrench */
2
+ (function (global, factory) {
3
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
4
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
5
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.bwCodeEdit = {}));
6
+ })(this, (function (exports) { 'use strict';
7
+
8
+ /**
9
+ * bitwrench-code-edit.js - syntax-highlighted contenteditable code editor addon
10
+ *
11
+ * Provides bw.highlight() for tokenizing JS/CSS/HTML into TACO spans,
12
+ * and bw.codeEditor() for a live editable code block with syntax coloring.
13
+ *
14
+ * Can be loaded standalone (browser script tag after bitwrench.umd.js),
15
+ * or imported as an ES module / CJS module.
16
+ *
17
+ * @module bitwrench-code-edit
18
+ * @license BSD-2-Clause
19
+ */
20
+
21
+ // -- CSS (injected once) ----------------------------------------------
22
+ var _cssInjected = false;
23
+ var CSS_TEXT = '.bw-ce{background:#1e293b;border-radius:6px;border:1px solid rgba(255,255,255,0.08);overflow:auto}' + '.bw-ce pre{margin:0;padding:0}' + '.bw-ce code{font-family:"SF Mono",Monaco,"Cascadia Code",Consolas,monospace;font-size:0.875rem;line-height:1.6;color:#e2e8f0;outline:none;white-space:pre-wrap;display:block;padding:0.75rem 1rem}' + '.bw-ce code:empty::before{content:"\\200b"}' + '.bw-ce .bw-ce-keyword{color:#c792ea}' + '.bw-ce .bw-ce-string{color:#c3e88d}' + '.bw-ce .bw-ce-comment{color:#546e7a;font-style:italic}' + '.bw-ce .bw-ce-number{color:#f78c6c}' + '.bw-ce .bw-ce-operator{color:#89ddff}' + '.bw-ce .bw-ce-punctuation{color:#89ddff}' + '.bw-ce .bw-ce-property{color:#82aaff}' + '.bw-ce .bw-ce-function{color:#82aaff}' + '.bw-ce .bw-ce-tag{color:#f07178}' + '.bw-ce .bw-ce-attr-name{color:#ffcb6b}' + '.bw-ce .bw-ce-attr-value{color:#c3e88d}' + '.bw-ce .bw-ce-selector{color:#c792ea}' + '.bw-ce .bw-ce-css-prop{color:#82aaff}' + '.bw-ce .bw-ce-css-value{color:#f78c6c}' + '.bw-ce .bw-ce-at-rule{color:#c792ea;font-style:italic}' + '.bw-ce .bw-ce-color{color:#f78c6c}' + '.bw-ce .bw-ce-template-interp{color:#89ddff}' +
24
+ // Light theme
25
+ '.bw-ce-light.bw-ce{background:#fafafa;border-color:#d8d8d8}' + '.bw-ce-light.bw-ce code{color:#1a1a1a}' + '.bw-ce-light.bw-ce .bw-ce-keyword{color:#7c3aed}' + '.bw-ce-light.bw-ce .bw-ce-string{color:#16a34a}' + '.bw-ce-light.bw-ce .bw-ce-comment{color:#9ca3af;font-style:italic}' + '.bw-ce-light.bw-ce .bw-ce-number{color:#ea580c}' + '.bw-ce-light.bw-ce .bw-ce-operator{color:#0891b2}' + '.bw-ce-light.bw-ce .bw-ce-punctuation{color:#6b7280}' + '.bw-ce-light.bw-ce .bw-ce-property{color:#2563eb}' + '.bw-ce-light.bw-ce .bw-ce-function{color:#2563eb}' + '.bw-ce-light.bw-ce .bw-ce-tag{color:#dc2626}' + '.bw-ce-light.bw-ce .bw-ce-attr-name{color:#d97706}' + '.bw-ce-light.bw-ce .bw-ce-attr-value{color:#16a34a}' + '.bw-ce-light.bw-ce .bw-ce-selector{color:#7c3aed}' + '.bw-ce-light.bw-ce .bw-ce-css-prop{color:#2563eb}' + '.bw-ce-light.bw-ce .bw-ce-css-value{color:#ea580c}' + '.bw-ce-light.bw-ce .bw-ce-at-rule{color:#7c3aed}' + '.bw-ce-light.bw-ce .bw-ce-color{color:#ea580c}' + '.bw-ce-light.bw-ce .bw-ce-template-interp{color:#0891b2}';
26
+ function ensureCSS(bw) {
27
+ if (_cssInjected) return;
28
+ _cssInjected = true;
29
+ if (bw && bw.injectCSS) {
30
+ bw.injectCSS(CSS_TEXT, {
31
+ id: 'bw-code-edit-styles'
32
+ });
33
+ }
34
+ }
35
+
36
+ // -- JS keywords ------------------------------------------------------
37
+ var JS_KEYWORDS = {};
38
+ 'var,const,let,function,return,if,else,for,while,do,switch,case,break,continue,new,typeof,instanceof,this,class,extends,import,export,default,from,true,false,null,undefined,try,catch,throw,finally,async,await,yield,of,in,delete,void,with,super,static,get,set,debugger'.split(',').forEach(function (k) {
39
+ JS_KEYWORDS[k] = true;
40
+ });
41
+
42
+ // -- JS Tokenizer -----------------------------------------------------
43
+ function tokenizeJS(code) {
44
+ var tokens = [];
45
+ var i = 0,
46
+ len = code.length;
47
+ var buf = '';
48
+ function flush(type) {
49
+ if (buf.length) {
50
+ tokens.push({
51
+ type: type,
52
+ text: buf
53
+ });
54
+ buf = '';
55
+ }
56
+ }
57
+ while (i < len) {
58
+ var ch = code[i];
59
+ var next = code[i + 1];
60
+
61
+ // Line comment
62
+ if (ch === '/' && next === '/') {
63
+ flush('plain');
64
+ var end = code.indexOf('\n', i);
65
+ if (end === -1) end = len;
66
+ tokens.push({
67
+ type: 'comment',
68
+ text: code.substring(i, end)
69
+ });
70
+ i = end;
71
+ continue;
72
+ }
73
+
74
+ // Block comment
75
+ if (ch === '/' && next === '*') {
76
+ flush('plain');
77
+ var end2 = code.indexOf('*/', i + 2);
78
+ if (end2 === -1) end2 = len - 2;
79
+ tokens.push({
80
+ type: 'comment',
81
+ text: code.substring(i, end2 + 2)
82
+ });
83
+ i = end2 + 2;
84
+ continue;
85
+ }
86
+
87
+ // Regex (simple heuristic: / after operator or start-of-line)
88
+ if (ch === '/' && next !== '/' && next !== '*') {
89
+ var prevToken = tokens.length ? tokens[tokens.length - 1] : null;
90
+ var prevBuf = buf.trim();
91
+ var isRegex = false;
92
+ if (!prevBuf.length) {
93
+ if (!prevToken) isRegex = true;else if (prevToken.type === 'operator' || prevToken.type === 'punctuation' || prevToken.type === 'keyword') isRegex = true;
94
+ }
95
+ if (isRegex) {
96
+ flush('plain');
97
+ var rBuf = '/';
98
+ var ri = i + 1;
99
+ var escaped = false;
100
+ var inCharClass = false;
101
+ while (ri < len) {
102
+ var rc = code[ri];
103
+ if (escaped) {
104
+ rBuf += rc;
105
+ escaped = false;
106
+ ri++;
107
+ continue;
108
+ }
109
+ if (rc === '\\') {
110
+ escaped = true;
111
+ rBuf += rc;
112
+ ri++;
113
+ continue;
114
+ }
115
+ if (rc === '[') {
116
+ inCharClass = true;
117
+ rBuf += rc;
118
+ ri++;
119
+ continue;
120
+ }
121
+ if (rc === ']') {
122
+ inCharClass = false;
123
+ rBuf += rc;
124
+ ri++;
125
+ continue;
126
+ }
127
+ if (rc === '/' && !inCharClass) {
128
+ rBuf += rc;
129
+ ri++;
130
+ break;
131
+ }
132
+ if (rc === '\n') break;
133
+ rBuf += rc;
134
+ ri++;
135
+ }
136
+ // Flags
137
+ while (ri < len && /[gimsuvy]/.test(code[ri])) {
138
+ rBuf += code[ri];
139
+ ri++;
140
+ }
141
+ tokens.push({
142
+ type: 'string',
143
+ text: rBuf
144
+ });
145
+ i = ri;
146
+ continue;
147
+ }
148
+ }
149
+
150
+ // Strings
151
+ if (ch === '"' || ch === "'" || ch === '`') {
152
+ flush('plain');
153
+ var quote = ch;
154
+ var sBuf = ch;
155
+ var si = i + 1;
156
+ if (quote === '`') {
157
+ // Template literal
158
+ while (si < len) {
159
+ var sc = code[si];
160
+ if (sc === '\\') {
161
+ sBuf += sc + (code[si + 1] || '');
162
+ si += 2;
163
+ continue;
164
+ }
165
+ if (sc === '$' && code[si + 1] === '{') {
166
+ // Flush string part so far
167
+ if (sBuf.length) tokens.push({
168
+ type: 'string',
169
+ text: sBuf
170
+ });
171
+ sBuf = '';
172
+ // Find matching brace (simple: count braces)
173
+ tokens.push({
174
+ type: 'template-interp',
175
+ text: '${'
176
+ });
177
+ si += 2;
178
+ var depth = 1;
179
+ var interpBuf = '';
180
+ while (si < len && depth > 0) {
181
+ if (code[si] === '{') depth++;else if (code[si] === '}') {
182
+ depth--;
183
+ if (depth === 0) break;
184
+ }
185
+ interpBuf += code[si];
186
+ si++;
187
+ }
188
+ // Tokenize the interpolation content recursively
189
+ var interpTokens = tokenizeJS(interpBuf);
190
+ tokens = tokens.concat(interpTokens);
191
+ tokens.push({
192
+ type: 'template-interp',
193
+ text: '}'
194
+ });
195
+ si++; // skip closing }
196
+ continue;
197
+ }
198
+ if (sc === '`') {
199
+ sBuf += sc;
200
+ si++;
201
+ break;
202
+ }
203
+ sBuf += sc;
204
+ si++;
205
+ }
206
+ if (sBuf.length) tokens.push({
207
+ type: 'string',
208
+ text: sBuf
209
+ });
210
+ } else {
211
+ while (si < len) {
212
+ var sc2 = code[si];
213
+ if (sc2 === '\\') {
214
+ sBuf += sc2 + (code[si + 1] || '');
215
+ si += 2;
216
+ continue;
217
+ }
218
+ if (sc2 === quote) {
219
+ sBuf += sc2;
220
+ si++;
221
+ break;
222
+ }
223
+ if (sc2 === '\n') break;
224
+ sBuf += sc2;
225
+ si++;
226
+ }
227
+ tokens.push({
228
+ type: 'string',
229
+ text: sBuf
230
+ });
231
+ }
232
+ i = si;
233
+ continue;
234
+ }
235
+
236
+ // Numbers
237
+ if (/[0-9]/.test(ch) || ch === '.' && next && /[0-9]/.test(next)) {
238
+ flush('plain');
239
+ var nBuf = '';
240
+ if (ch === '0' && next && /[xXbBoO]/.test(next)) {
241
+ nBuf = ch + next;
242
+ i += 2;
243
+ while (i < len && /[0-9a-fA-F_]/.test(code[i])) {
244
+ nBuf += code[i];
245
+ i++;
246
+ }
247
+ } else {
248
+ while (i < len && /[0-9._eE]/.test(code[i])) {
249
+ if ((code[i] === 'e' || code[i] === 'E') && code[i + 1] && /[+\-0-9]/.test(code[i + 1])) {
250
+ nBuf += code[i] + code[i + 1];
251
+ i += 2;
252
+ continue;
253
+ }
254
+ nBuf += code[i];
255
+ i++;
256
+ }
257
+ }
258
+ tokens.push({
259
+ type: 'number',
260
+ text: nBuf
261
+ });
262
+ continue;
263
+ }
264
+
265
+ // Identifiers / keywords
266
+ if (/[a-zA-Z_$]/.test(ch)) {
267
+ flush('plain');
268
+ var wBuf = '';
269
+ while (i < len && /[a-zA-Z0-9_$]/.test(code[i])) {
270
+ wBuf += code[i];
271
+ i++;
272
+ }
273
+ // Look-ahead: is it a function call?
274
+ var la = i;
275
+ while (la < len && (code[la] === ' ' || code[la] === '\t')) la++;
276
+ // Look-back: is it a property (after dot)?
277
+ var prevTok = tokens.length ? tokens[tokens.length - 1] : null;
278
+ var isDot = prevTok && prevTok.type === 'punctuation' && prevTok.text === '.';
279
+ if (JS_KEYWORDS[wBuf]) {
280
+ tokens.push({
281
+ type: 'keyword',
282
+ text: wBuf
283
+ });
284
+ } else if (isDot) {
285
+ if (la < len && code[la] === '(') {
286
+ tokens.push({
287
+ type: 'function',
288
+ text: wBuf
289
+ });
290
+ } else {
291
+ tokens.push({
292
+ type: 'property',
293
+ text: wBuf
294
+ });
295
+ }
296
+ } else if (la < len && code[la] === '(') {
297
+ tokens.push({
298
+ type: 'function',
299
+ text: wBuf
300
+ });
301
+ } else {
302
+ tokens.push({
303
+ type: 'plain',
304
+ text: wBuf
305
+ });
306
+ }
307
+ continue;
308
+ }
309
+
310
+ // Operators
311
+ if ('=+-*/%!<>&|^~?:'.indexOf(ch) !== -1) {
312
+ flush('plain');
313
+ // Consume multi-char operators
314
+ var opBuf = ch;
315
+ i++;
316
+ if (i < len && '=+-*/%!<>&|^~?:'.indexOf(code[i]) !== -1) {
317
+ opBuf += code[i];
318
+ i++;
319
+ if (i < len && '=>&|'.indexOf(code[i]) !== -1) {
320
+ opBuf += code[i];
321
+ i++;
322
+ }
323
+ }
324
+ tokens.push({
325
+ type: 'operator',
326
+ text: opBuf
327
+ });
328
+ continue;
329
+ }
330
+
331
+ // Punctuation
332
+ if ('(){}[];,.'.indexOf(ch) !== -1) {
333
+ flush('plain');
334
+ tokens.push({
335
+ type: 'punctuation',
336
+ text: ch
337
+ });
338
+ i++;
339
+ continue;
340
+ }
341
+
342
+ // Plain (whitespace + anything else)
343
+ buf += ch;
344
+ i++;
345
+ }
346
+ flush('plain');
347
+ return tokens;
348
+ }
349
+
350
+ // -- CSS Tokenizer ----------------------------------------------------
351
+ function tokenizeCSS(code) {
352
+ var tokens = [];
353
+ var i = 0,
354
+ len = code.length;
355
+ var state = 'selector'; // selector | prop | value
356
+ var buf = '';
357
+ function flush(type) {
358
+ if (buf.length) {
359
+ tokens.push({
360
+ type: type || 'plain',
361
+ text: buf
362
+ });
363
+ buf = '';
364
+ }
365
+ }
366
+ while (i < len) {
367
+ var ch = code[i];
368
+ var next = code[i + 1];
369
+
370
+ // Block comment
371
+ if (ch === '/' && next === '*') {
372
+ flush(state === 'selector' ? 'selector' : state === 'prop' ? 'css-prop' : 'css-value');
373
+ var end = code.indexOf('*/', i + 2);
374
+ if (end === -1) end = len - 2;
375
+ tokens.push({
376
+ type: 'comment',
377
+ text: code.substring(i, end + 2)
378
+ });
379
+ i = end + 2;
380
+ continue;
381
+ }
382
+
383
+ // Strings in values
384
+ if ((ch === '"' || ch === "'") && (state === 'value' || state === 'selector')) {
385
+ flush(state === 'selector' ? 'selector' : 'css-value');
386
+ var quote = ch;
387
+ var sBuf = ch;
388
+ i++;
389
+ while (i < len) {
390
+ if (code[i] === '\\') {
391
+ sBuf += code[i] + (code[i + 1] || '');
392
+ i += 2;
393
+ continue;
394
+ }
395
+ if (code[i] === quote) {
396
+ sBuf += code[i];
397
+ i++;
398
+ break;
399
+ }
400
+ sBuf += code[i];
401
+ i++;
402
+ }
403
+ tokens.push({
404
+ type: 'string',
405
+ text: sBuf
406
+ });
407
+ continue;
408
+ }
409
+
410
+ // At-rules
411
+ if (ch === '@' && state === 'selector') {
412
+ flush('selector');
413
+ var aBuf = '@';
414
+ i++;
415
+ while (i < len && /[a-zA-Z\-]/.test(code[i])) {
416
+ aBuf += code[i];
417
+ i++;
418
+ }
419
+ tokens.push({
420
+ type: 'at-rule',
421
+ text: aBuf
422
+ });
423
+ continue;
424
+ }
425
+
426
+ // Hex colors in values
427
+ if (ch === '#' && state === 'value') {
428
+ flush('css-value');
429
+ var hBuf = '#';
430
+ i++;
431
+ while (i < len && /[0-9a-fA-F]/.test(code[i])) {
432
+ hBuf += code[i];
433
+ i++;
434
+ }
435
+ tokens.push({
436
+ type: 'color',
437
+ text: hBuf
438
+ });
439
+ continue;
440
+ }
441
+
442
+ // Numbers in values
443
+ if (state === 'value' && /[0-9]/.test(ch)) {
444
+ flush('css-value');
445
+ var nBuf2 = '';
446
+ while (i < len && /[0-9.]/.test(code[i])) {
447
+ nBuf2 += code[i];
448
+ i++;
449
+ }
450
+ // Unit
451
+ var uBuf = '';
452
+ while (i < len && /[a-zA-Z%]/.test(code[i])) {
453
+ uBuf += code[i];
454
+ i++;
455
+ }
456
+ tokens.push({
457
+ type: 'number',
458
+ text: nBuf2 + uBuf
459
+ });
460
+ continue;
461
+ }
462
+
463
+ // Punctuation and state transitions
464
+ if (ch === '{') {
465
+ flush(state === 'selector' ? 'selector' : 'plain');
466
+ tokens.push({
467
+ type: 'punctuation',
468
+ text: ch
469
+ });
470
+ state = 'prop';
471
+ i++;
472
+ continue;
473
+ }
474
+ if (ch === '}') {
475
+ flush(state === 'prop' ? 'css-prop' : state === 'value' ? 'css-value' : 'plain');
476
+ tokens.push({
477
+ type: 'punctuation',
478
+ text: ch
479
+ });
480
+ state = 'selector';
481
+ i++;
482
+ continue;
483
+ }
484
+ if (ch === ':' && state === 'prop') {
485
+ flush('css-prop');
486
+ tokens.push({
487
+ type: 'punctuation',
488
+ text: ch
489
+ });
490
+ state = 'value';
491
+ i++;
492
+ continue;
493
+ }
494
+ if (ch === ';') {
495
+ flush(state === 'value' ? 'css-value' : 'plain');
496
+ tokens.push({
497
+ type: 'punctuation',
498
+ text: ch
499
+ });
500
+ state = 'prop';
501
+ i++;
502
+ continue;
503
+ }
504
+ if (ch === ',') {
505
+ flush(state === 'selector' ? 'selector' : state === 'value' ? 'css-value' : 'plain');
506
+ tokens.push({
507
+ type: 'punctuation',
508
+ text: ch
509
+ });
510
+ i++;
511
+ continue;
512
+ }
513
+
514
+ // Accumulate into buffer
515
+ buf += ch;
516
+ i++;
517
+ }
518
+ flush(state === 'selector' ? 'selector' : state === 'prop' ? 'css-prop' : 'css-value');
519
+ return tokens;
520
+ }
521
+
522
+ // -- HTML Tokenizer ---------------------------------------------------
523
+ function tokenizeHTML(code) {
524
+ var tokens = [];
525
+ var i = 0,
526
+ len = code.length;
527
+ var buf = '';
528
+ function flush(type) {
529
+ if (buf.length) {
530
+ tokens.push({
531
+ type: type,
532
+ text: buf
533
+ });
534
+ buf = '';
535
+ }
536
+ }
537
+ while (i < len) {
538
+ var ch = code[i];
539
+
540
+ // Comment
541
+ if (ch === '<' && code.substring(i, i + 4) === '<!--') {
542
+ flush('plain');
543
+ var end = code.indexOf('-->', i + 4);
544
+ if (end === -1) end = len - 3;
545
+ tokens.push({
546
+ type: 'comment',
547
+ text: code.substring(i, end + 3)
548
+ });
549
+ i = end + 3;
550
+ continue;
551
+ }
552
+
553
+ // Tag
554
+ if (ch === '<') {
555
+ flush('plain');
556
+ // Consume < and optional /
557
+ var tBuf = '<';
558
+ i++;
559
+ if (i < len && code[i] === '/') {
560
+ tBuf += '/';
561
+ i++;
562
+ }
563
+ // Tag name
564
+ while (i < len && /[a-zA-Z0-9\-]/.test(code[i])) {
565
+ tBuf += code[i];
566
+ i++;
567
+ }
568
+ tokens.push({
569
+ type: 'tag',
570
+ text: tBuf
571
+ });
572
+
573
+ // Attributes
574
+ while (i < len && code[i] !== '>' && !(code[i] === '/' && code[i + 1] === '>')) {
575
+ // Whitespace
576
+ if (/\s/.test(code[i])) {
577
+ var wBuf = '';
578
+ while (i < len && /\s/.test(code[i])) {
579
+ wBuf += code[i];
580
+ i++;
581
+ }
582
+ tokens.push({
583
+ type: 'plain',
584
+ text: wBuf
585
+ });
586
+ continue;
587
+ }
588
+ // Attribute name
589
+ if (/[a-zA-Z_\-@:]/.test(code[i])) {
590
+ var aBuf = '';
591
+ while (i < len && /[a-zA-Z0-9_\-@:]/.test(code[i])) {
592
+ aBuf += code[i];
593
+ i++;
594
+ }
595
+ tokens.push({
596
+ type: 'attr-name',
597
+ text: aBuf
598
+ });
599
+ // = sign
600
+ if (i < len && code[i] === '=') {
601
+ tokens.push({
602
+ type: 'punctuation',
603
+ text: '='
604
+ });
605
+ i++;
606
+ // Attribute value
607
+ if (i < len && (code[i] === '"' || code[i] === "'")) {
608
+ var q = code[i];
609
+ var vBuf = q;
610
+ i++;
611
+ while (i < len && code[i] !== q) {
612
+ vBuf += code[i];
613
+ i++;
614
+ }
615
+ if (i < len) {
616
+ vBuf += code[i];
617
+ i++;
618
+ }
619
+ tokens.push({
620
+ type: 'attr-value',
621
+ text: vBuf
622
+ });
623
+ } else {
624
+ // Unquoted value
625
+ var uBuf2 = '';
626
+ while (i < len && !/[\s>]/.test(code[i])) {
627
+ uBuf2 += code[i];
628
+ i++;
629
+ }
630
+ tokens.push({
631
+ type: 'attr-value',
632
+ text: uBuf2
633
+ });
634
+ }
635
+ }
636
+ continue;
637
+ }
638
+ // Anything else in tag
639
+ buf += code[i];
640
+ i++;
641
+ flush('plain');
642
+ }
643
+
644
+ // Close of tag
645
+ var closeBuf = '';
646
+ if (i < len && code[i] === '/') {
647
+ closeBuf += '/';
648
+ i++;
649
+ }
650
+ if (i < len && code[i] === '>') {
651
+ closeBuf += '>';
652
+ i++;
653
+ }
654
+ if (closeBuf) tokens.push({
655
+ type: 'tag',
656
+ text: closeBuf
657
+ });
658
+ continue;
659
+ }
660
+
661
+ // Entity
662
+ if (ch === '&') {
663
+ flush('plain');
664
+ var eBuf = '&';
665
+ i++;
666
+ while (i < len && code[i] !== ';' && /[a-zA-Z0-9#]/.test(code[i])) {
667
+ eBuf += code[i];
668
+ i++;
669
+ }
670
+ if (i < len && code[i] === ';') {
671
+ eBuf += ';';
672
+ i++;
673
+ }
674
+ tokens.push({
675
+ type: 'string',
676
+ text: eBuf
677
+ });
678
+ continue;
679
+ }
680
+
681
+ // Plain text
682
+ buf += ch;
683
+ i++;
684
+ }
685
+ flush('plain');
686
+ return tokens;
687
+ }
688
+
689
+ // -- Token to TACO conversion -----------------------------------------
690
+ var TOKENIZERS = {
691
+ js: tokenizeJS,
692
+ javascript: tokenizeJS,
693
+ css: tokenizeCSS,
694
+ html: tokenizeHTML
695
+ };
696
+ function tokensToTACO(tokArr) {
697
+ var result = [];
698
+ for (var i = 0; i < tokArr.length; i++) {
699
+ var tok = tokArr[i];
700
+ if (tok.type === 'plain') {
701
+ result.push(tok.text);
702
+ } else {
703
+ result.push({
704
+ t: 'span',
705
+ a: {
706
+ "class": 'bw-ce-' + tok.type
707
+ },
708
+ c: tok.text
709
+ });
710
+ }
711
+ }
712
+ return result;
713
+ }
714
+
715
+ // -- Public: highlight ------------------------------------------------
716
+ function highlight(code, lang) {
717
+ var tokenizer = TOKENIZERS[lang] || tokenizeJS;
718
+ var tokens = tokenizer(code);
719
+ return tokensToTACO(tokens);
720
+ }
721
+
722
+ // -- Caret save/restore -----------------------------------------------
723
+ function getCaretOffset(el) {
724
+ var sel = window.getSelection();
725
+ if (!sel.rangeCount) return 0;
726
+ var range = sel.getRangeAt(0).cloneRange();
727
+ range.selectNodeContents(el);
728
+ range.setEnd(sel.getRangeAt(0).startContainer, sel.getRangeAt(0).startOffset);
729
+ return range.toString().length;
730
+ }
731
+ function setCaretOffset(el, offset) {
732
+ var sel = window.getSelection();
733
+ var range = document.createRange();
734
+ var walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null, false);
735
+ var pos = 0;
736
+ var node;
737
+ while (node = walker.nextNode()) {
738
+ var nodeLen = node.textContent.length;
739
+ if (pos + nodeLen >= offset) {
740
+ range.setStart(node, offset - pos);
741
+ range.collapse(true);
742
+ sel.removeAllRanges();
743
+ sel.addRange(range);
744
+ return;
745
+ }
746
+ pos += nodeLen;
747
+ }
748
+ // If offset exceeds content, place at end
749
+ range.selectNodeContents(el);
750
+ range.collapse(false);
751
+ sel.removeAllRanges();
752
+ sel.addRange(range);
753
+ }
754
+
755
+ // -- Public: codeEditor -----------------------------------------------
756
+ function codeEditor(opts) {
757
+ opts = opts || {};
758
+ var code = opts.code || '';
759
+ var lang = opts.lang || 'js';
760
+ var height = opts.height || '180px';
761
+ var readOnly = !!opts.readOnly;
762
+ var className = 'bw-ce' + (opts.className ? ' ' + opts.className : '');
763
+ var highlighted = highlight(code, lang);
764
+ var codeAttrs = {
765
+ spellcheck: 'false',
766
+ "class": 'bw-ce-code'
767
+ };
768
+ if (!readOnly) {
769
+ codeAttrs.contenteditable = 'true';
770
+ }
771
+ return {
772
+ t: 'div',
773
+ a: {
774
+ "class": className,
775
+ style: 'max-height:' + height + ';overflow:auto'
776
+ },
777
+ c: [{
778
+ t: 'pre',
779
+ c: {
780
+ t: 'code',
781
+ a: codeAttrs,
782
+ c: highlighted
783
+ }
784
+ }],
785
+ o: {
786
+ mounted: function mounted(el) {
787
+ var codeEl = el.querySelector('.bw-ce-code');
788
+ if (!codeEl) return;
789
+ var currentCode = code;
790
+ var debounceTimer = null;
791
+
792
+ // Resolve bw from global or import context
793
+ var bw = typeof window !== 'undefined' && window.bw || {};
794
+ function getValue() {
795
+ return codeEl.textContent || '';
796
+ }
797
+ function setValue(newCode) {
798
+ currentCode = newCode;
799
+ var tacos = highlight(newCode, lang);
800
+ if (bw.html) codeEl.innerHTML = bw.html({
801
+ t: 'span',
802
+ c: tacos
803
+ });
804
+ }
805
+
806
+ // Expose API on the element
807
+ el._bwCodeEdit = {
808
+ getValue: getValue,
809
+ setValue: setValue
810
+ };
811
+ if (readOnly) return;
812
+ function rehighlight() {
813
+ var newCode = getValue();
814
+ if (newCode === currentCode) return;
815
+ currentCode = newCode;
816
+ var offset = getCaretOffset(codeEl);
817
+ var tacos = highlight(newCode, lang);
818
+ if (bw.html) codeEl.innerHTML = bw.html({
819
+ t: 'span',
820
+ c: tacos
821
+ });
822
+ setCaretOffset(codeEl, offset);
823
+ if (opts.onChange) opts.onChange(newCode);
824
+ }
825
+ codeEl.addEventListener('input', function () {
826
+ clearTimeout(debounceTimer);
827
+ debounceTimer = setTimeout(rehighlight, 50);
828
+ });
829
+
830
+ // Tab key: insert 2 spaces
831
+ codeEl.addEventListener('keydown', function (e) {
832
+ if (e.key === 'Tab') {
833
+ e.preventDefault();
834
+ document.execCommand('insertText', false, ' ');
835
+ }
836
+ });
837
+ }
838
+ }
839
+ };
840
+ }
841
+
842
+ // -- Auto-attach to bw when loaded as script tag ----------------------
843
+ function install(bw) {
844
+ if (!bw) return;
845
+ bw.highlight = highlight;
846
+ bw.codeEditor = function (opts) {
847
+ ensureCSS(bw);
848
+ return codeEditor(opts);
849
+ };
850
+ }
851
+
852
+ // Auto-install if bw is on window (script tag usage)
853
+ if (typeof window !== 'undefined' && window.bw) {
854
+ install(window.bw);
855
+ }
856
+ var bitwrenchCodeEdit = {
857
+ highlight: highlight,
858
+ codeEditor: codeEditor,
859
+ install: install,
860
+ CSS_TEXT: CSS_TEXT
861
+ };
862
+
863
+ exports.CSS_TEXT = CSS_TEXT;
864
+ exports.codeEditor = codeEditor;
865
+ exports.default = bitwrenchCodeEdit;
866
+ exports.highlight = highlight;
867
+ exports.install = install;
868
+ exports.tokenizeCSS = tokenizeCSS;
869
+ exports.tokenizeHTML = tokenizeHTML;
870
+ exports.tokenizeJS = tokenizeJS;
871
+
872
+ Object.defineProperty(exports, '__esModule', { value: true });
873
+
874
+ }));
875
+ //# sourceMappingURL=bitwrench-code-edit.es5.js.map