bitwrench 2.0.19 → 2.0.21
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 +0 -2
- package/dist/bitwrench-bccl.cjs.js +1 -1
- package/dist/bitwrench-bccl.cjs.min.js +1 -1
- package/dist/bitwrench-bccl.esm.js +1 -1
- package/dist/bitwrench-bccl.esm.min.js +1 -1
- package/dist/bitwrench-bccl.umd.js +1 -1
- package/dist/bitwrench-bccl.umd.min.js +1 -1
- package/dist/bitwrench-code-edit.cjs.js +1 -1
- package/dist/bitwrench-code-edit.cjs.min.js +1 -1
- package/dist/bitwrench-code-edit.es5.js +1 -1
- package/dist/bitwrench-code-edit.es5.min.js +1 -1
- package/dist/bitwrench-code-edit.esm.js +1 -1
- package/dist/bitwrench-code-edit.esm.min.js +1 -1
- package/dist/bitwrench-code-edit.umd.js +1 -1
- package/dist/bitwrench-code-edit.umd.min.js +1 -1
- package/dist/bitwrench-debug.js +1 -1
- package/dist/bitwrench-debug.min.js +1 -1
- package/dist/bitwrench-lean.cjs.js +344 -30
- package/dist/bitwrench-lean.cjs.min.js +14 -6
- package/dist/bitwrench-lean.es5.js +379 -29
- package/dist/bitwrench-lean.es5.min.js +12 -4
- package/dist/bitwrench-lean.esm.js +344 -30
- package/dist/bitwrench-lean.esm.min.js +14 -6
- package/dist/bitwrench-lean.umd.js +344 -30
- package/dist/bitwrench-lean.umd.min.js +14 -6
- package/dist/bitwrench-util-css.cjs.js +1 -1
- package/dist/bitwrench-util-css.cjs.min.js +1 -1
- package/dist/bitwrench-util-css.es5.js +1 -1
- package/dist/bitwrench-util-css.es5.min.js +1 -1
- package/dist/bitwrench-util-css.esm.js +1 -1
- package/dist/bitwrench-util-css.esm.min.js +1 -1
- package/dist/bitwrench-util-css.umd.js +1 -1
- package/dist/bitwrench-util-css.umd.min.js +1 -1
- package/dist/bitwrench.cjs.js +344 -30
- package/dist/bitwrench.cjs.min.js +14 -6
- package/dist/bitwrench.css +65 -14
- package/dist/bitwrench.es5.js +379 -29
- package/dist/bitwrench.es5.min.js +13 -5
- package/dist/bitwrench.esm.js +344 -30
- package/dist/bitwrench.esm.min.js +15 -7
- package/dist/bitwrench.min.css +1 -1
- package/dist/bitwrench.umd.js +344 -30
- package/dist/bitwrench.umd.min.js +14 -6
- package/dist/builds.json +94 -94
- package/dist/bwserve.cjs.js +2 -2
- package/dist/bwserve.esm.js +2 -2
- package/dist/sri.json +46 -46
- package/package.json +5 -6
- package/readme.html +2 -2
- package/src/bitwrench-router.js +282 -0
- package/src/bitwrench-styles.js +59 -27
- package/src/bitwrench.js +6 -0
- package/src/version.js +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bitwrench",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.21",
|
|
4
4
|
"description": "A library for javascript UI functions.",
|
|
5
5
|
"main": "./dist/bitwrench.umd.js",
|
|
6
6
|
"repository": {
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"dist/*.js",
|
|
44
44
|
"dist/*.css",
|
|
45
45
|
"dist/*.json",
|
|
46
|
+
"dist/*.d.ts",
|
|
46
47
|
"bin/",
|
|
47
48
|
"src/",
|
|
48
49
|
"README.md",
|
|
@@ -92,10 +93,9 @@
|
|
|
92
93
|
"build:readme": "node tools/build-readme.js",
|
|
93
94
|
"build:watch": "rollup --config --watch",
|
|
94
95
|
"update_rm": "echo 'DEPRECATED: use build:index instead'",
|
|
95
|
-
"build_1_x": "./tools/update-bw-package.js package.json package.json && ./tools/export-bw-default-css.js bitwrench.css && uglifyjs bitwrench.js -o bitwrench.min.js && uglifyjs bitwrench_ESM.js -o bitwrench_ESM.min.js && ./tools/umd2ModuleHack.js && npm pack",
|
|
96
96
|
"cleanbuild": "npm run clean && npm run build && npm run build:generated",
|
|
97
97
|
"oldtest": "./node_modules/mocha/bin/mocha test/bitwrench_test.js --reporter spec",
|
|
98
|
-
"test": "c8 --reporter=text mocha ./test/bitwrench_ci.js ./test/bitwrench_test_coverage.js ./test/bitwrench_test_pubsub.js ./test/bitwrench_test_theme.js ./test/bitwrench_test_nodemap.js ./test/bitwrench_test_components.js ./test/bitwrench_test_coverage_gaps.js ./test/bitwrench_test_bwserve.js ./test/bitwrench_test_attach.js ./test/bitwrench_test_serve.js ./test/bitwrench_test_code_edit.js ./test/bitwrench_test_html_page.js ./test/bitwrench_test_util_css.js ./test/bitwrench_test_handle.js ./test/bitwrench_test_debug.js -r jsdom-global/register",
|
|
98
|
+
"test": "c8 --reporter=text mocha ./test/bitwrench_ci.js ./test/bitwrench_test_coverage.js ./test/bitwrench_test_pubsub.js ./test/bitwrench_test_theme.js ./test/bitwrench_test_nodemap.js ./test/bitwrench_test_components.js ./test/bitwrench_test_coverage_gaps.js ./test/bitwrench_test_bwserve.js ./test/bitwrench_test_attach.js ./test/bitwrench_test_serve.js ./test/bitwrench_test_code_edit.js ./test/bitwrench_test_html_page.js ./test/bitwrench_test_util_css.js ./test/bitwrench_test_handle.js ./test/bitwrench_test_debug.js ./test/bitwrench_test_router.js -r jsdom-global/register",
|
|
99
99
|
"test:bwserve": "mocha ./test/bitwrench_test_bwserve.js -r jsdom-global/register",
|
|
100
100
|
"test:attach": "mocha ./test/bitwrench_test_attach.js -r jsdom-global/register",
|
|
101
101
|
"test:serve": "mocha ./test/bitwrench_test_serve.js -r jsdom-global/register --exit",
|
|
@@ -114,6 +114,7 @@
|
|
|
114
114
|
"test:nodemap": "mocha ./test/bitwrench_test_nodemap.js -r jsdom-global/register",
|
|
115
115
|
"test:cli": "mocha ./test/bitwrench_test_cli.js",
|
|
116
116
|
"test:debug": "mocha ./test/bitwrench_test_debug.js -r jsdom-global/register",
|
|
117
|
+
"test:router": "mocha ./test/bitwrench_test_router.js -r jsdom-global/register",
|
|
117
118
|
"test:code-edit": "mocha ./test/bitwrench_test_code_edit.js -r jsdom-global/register",
|
|
118
119
|
"test:html-page": "mocha ./test/bitwrench_test_html_page.js -r jsdom-global/register",
|
|
119
120
|
"test:e2e": "playwright test",
|
|
@@ -141,9 +142,7 @@
|
|
|
141
142
|
"include": [
|
|
142
143
|
"src/**"
|
|
143
144
|
],
|
|
144
|
-
"exclude": [
|
|
145
|
-
"src_1x/**"
|
|
146
|
-
],
|
|
145
|
+
"exclude": [],
|
|
147
146
|
"check-coverage": false,
|
|
148
147
|
"branches": 80,
|
|
149
148
|
"lines": 80,
|
package/readme.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<meta name="generator" content="bitwrench v2.0.
|
|
6
|
+
<meta name="generator" content="bitwrench v2.0.21">
|
|
7
7
|
<title>bitwrench.js - README</title>
|
|
8
8
|
<link rel="icon" type="image/x-icon" href="images/favicon.ico">
|
|
9
9
|
<script src="dist/bitwrench.umd.min.js"></script>
|
|
@@ -381,7 +381,7 @@ curl -X POST http://localhost:9000 -d '{"type":"patch",&
|
|
|
381
381
|
<li class="quikdown-li"><a class="quikdown-a" href="examples/client-server/">bwserve Counter</a> -- server-driven UI demo</li>
|
|
382
382
|
<li class="quikdown-li"><a class="quikdown-a" href="examples/llm-chat/">LLM Chat</a> -- streaming chat via bwserve + Ollama/OpenAI</li>
|
|
383
383
|
</ul><h2 class="quikdown-h2">FAQ</h2>
|
|
384
|
-
<strong class="quikdown-strong">Is this a framework?</strong> -- No. Bitwrench is a library (~38KB gzipped). No lifecycle to learn, no project structure to follow. Import it, call functions, done.</p><p><strong class="quikdown-strong">
|
|
384
|
+
<strong class="quikdown-strong">Is this a framework?</strong> -- No. Bitwrench is a library (~38KB gzipped). No lifecycle to learn, no project structure to follow. Import it, call functions, done.</p><p><strong class="quikdown-strong">How does bitwrench compare to React/Vue?</strong> -- They solve different problems at different scales. React and Vue provide a component model, virtual DOM, and ecosystem for large team-built SPAs. Bitwrench provides rendering and state primitives in a single file with no build step, aimed at single-page tools, dashboards, embedded devices, and server-driven UIs. They coexist fine -- use whichever fits the job.</p><p><strong class="quikdown-strong">How does CSS work?</strong> -- Bitwrench doesn't own your CSS. Use any external stylesheet, Tailwind, or CSS file you want -- bitwrench doesn't interfere. On top of that, <code class="quikdown-code">bw.css()</code> generates CSS from JS objects (with <code class="quikdown-code">@media</code>, <code class="quikdown-code">@keyframes</code>, pseudo-classes), <code class="quikdown-code">bw.s()</code> composes inline style objects, and <code class="quikdown-code">bw.loadStyles()</code> derives a complete design system from 2 seed colors. You can use all three together or none at all.</p><p><strong class="quikdown-strong">What's the difference between <code class="quikdown-code">bw.DOM()</code> and <code class="quikdown-code">bw.html()</code>?</strong> -- Same TACO input, two outputs. <code class="quikdown-code">bw.DOM('#app', taco)</code> mounts live DOM elements in a browser. <code class="quikdown-code">bw.html(taco)</code> returns an HTML string -- use it in Node.js scripts, email generators, static site builds, or anywhere you need markup without a browser. One object format, two rendering modes.</p><p><strong class="quikdown-strong">What is bwserve?</strong> -- bwserve lets any server push UI updates to a browser over SSE. The server sends TACO objects as JSON; the browser renders them. It's language-agnostic -- the server can be Python, Go, Rust, C, or a shell script. Anything that can write JSON to an HTTP response can drive a bitwrench UI. See the <a class="quikdown-a" href="docs/bwserve.md">bwserve docs</a>.</p><p><strong class="quikdown-strong">Can I use bitwrench on embedded devices?</strong> -- Yes -- this is a primary use case. An ESP32 or Raspberry Pi serves one HTML page with bitwrench loaded, then pushes sensor data as JSON patches over SSE. The device never generates HTML. See the <a class="quikdown-a" href="docs/tutorial-embedded.md">ESP32 tutorial</a>.</p><p><strong class="quikdown-strong">Can I use it with TypeScript?</strong> -- Yes. Type declarations are included. TACO objects are plain JSON-compatible objects that TypeScript infers naturally.</p><p><strong class="quikdown-strong">What about accessibility?</strong> -- BCCL components emit semantic HTML with ARIA attributes where applicable. You can add any <code class="quikdown-code">aria-*</code> attribute via <code class="quikdown-code">a: { 'aria-label': '...' }</code>.</p><h2 class="quikdown-h2">Development</h2>
|
|
385
385
|
<p><pre class="quikdown-pre"><code class="language-bash">npm install # install dev dependencies
|
|
386
386
|
npm run build # build all dist formats (UMD, ESM, CJS, ES5)
|
|
387
387
|
npm test # run unit tests (1400+ tests, 96% coverage)
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bitwrench Router -- client-side URL routing for SPAs
|
|
3
|
+
*
|
|
4
|
+
* Single export: initRouter(bw) attaches bw.router(), bw.navigate(), bw.link()
|
|
5
|
+
*
|
|
6
|
+
* @license BSD-2-Clause
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// -- internal helpers --
|
|
10
|
+
|
|
11
|
+
function normalizePath(p) {
|
|
12
|
+
// strip query string (handled separately)
|
|
13
|
+
var qi = p.indexOf('?');
|
|
14
|
+
if (qi >= 0) p = p.substring(0, qi);
|
|
15
|
+
// collapse double slashes, strip trailing slash
|
|
16
|
+
p = p.replace(/\/\/+/g, '/');
|
|
17
|
+
if (p.length > 1 && p.charAt(p.length - 1) === '/') p = p.substring(0, p.length - 1);
|
|
18
|
+
return p || '/';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function parseQuery(fullPath) {
|
|
22
|
+
var qi = fullPath.indexOf('?');
|
|
23
|
+
if (qi < 0) return {};
|
|
24
|
+
var qs = fullPath.substring(qi + 1);
|
|
25
|
+
var result = {};
|
|
26
|
+
var pairs = qs.split('&');
|
|
27
|
+
for (var i = 0; i < pairs.length; i++) {
|
|
28
|
+
var kv = pairs[i].split('=');
|
|
29
|
+
if (kv[0]) result[decodeURIComponent(kv[0])] = kv.length > 1 ? decodeURIComponent(kv[1]) : '';
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function matchRoute(routes, rawPath) {
|
|
35
|
+
var query = parseQuery(rawPath);
|
|
36
|
+
var path = normalizePath(rawPath);
|
|
37
|
+
var segs = path === '/' ? [''] : path.split('/');
|
|
38
|
+
|
|
39
|
+
var globalWild = null;
|
|
40
|
+
|
|
41
|
+
for (var i = 0; i < routes.length; i++) {
|
|
42
|
+
var r = routes[i];
|
|
43
|
+
var pattern = r.pattern;
|
|
44
|
+
|
|
45
|
+
// global wildcard -- save for last
|
|
46
|
+
if (pattern === '*') { globalWild = r; continue; }
|
|
47
|
+
|
|
48
|
+
// catch-all: ends with /*
|
|
49
|
+
if (pattern.length > 1 && pattern.substring(pattern.length - 2) === '/*') {
|
|
50
|
+
var prefix = pattern.substring(0, pattern.length - 2);
|
|
51
|
+
var prefixSegs = prefix === '' ? [''] : prefix.split('/');
|
|
52
|
+
if (segs.length < prefixSegs.length) continue;
|
|
53
|
+
var params = {};
|
|
54
|
+
var ok = true;
|
|
55
|
+
for (var j = 0; j < prefixSegs.length; j++) {
|
|
56
|
+
if (prefixSegs[j].charAt(0) === ':') {
|
|
57
|
+
params[prefixSegs[j].substring(1)] = segs[j];
|
|
58
|
+
} else if (prefixSegs[j] !== segs[j]) {
|
|
59
|
+
ok = false; break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (ok) {
|
|
63
|
+
params._rest = segs.slice(prefixSegs.length).join('/');
|
|
64
|
+
params._query = query;
|
|
65
|
+
return { handler: r.handler, params: params };
|
|
66
|
+
}
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// exact / parameterized match
|
|
71
|
+
var rSegs = pattern === '/' ? [''] : pattern.split('/');
|
|
72
|
+
if (rSegs.length !== segs.length) continue;
|
|
73
|
+
var params2 = {};
|
|
74
|
+
var match = true;
|
|
75
|
+
for (var k = 0; k < rSegs.length; k++) {
|
|
76
|
+
if (rSegs[k].charAt(0) === ':') {
|
|
77
|
+
params2[rSegs[k].substring(1)] = segs[k];
|
|
78
|
+
} else if (rSegs[k] !== segs[k]) {
|
|
79
|
+
match = false; break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (match) {
|
|
83
|
+
params2._query = query;
|
|
84
|
+
return { handler: r.handler, params: params2 };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// global wildcard fallback
|
|
89
|
+
if (globalWild) {
|
|
90
|
+
return { handler: globalWild.handler, params: { _query: query } };
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
// -- public API factory --
|
|
97
|
+
|
|
98
|
+
export function initRouter(bw) {
|
|
99
|
+
var _activeRouter = null;
|
|
100
|
+
|
|
101
|
+
bw.router = function(config) {
|
|
102
|
+
if (!config || !config.routes) throw new Error('bw.router: config.routes is required');
|
|
103
|
+
if (!bw._isBrowser) throw new Error('bw.router: requires a browser environment');
|
|
104
|
+
|
|
105
|
+
var mode = config.mode || 'hash';
|
|
106
|
+
var base = config.base || '/';
|
|
107
|
+
if (base.length > 1 && base.charAt(base.length - 1) === '/') base = base.substring(0, base.length - 1);
|
|
108
|
+
var target = config.target || null;
|
|
109
|
+
|
|
110
|
+
// compile routes (preserve registration order)
|
|
111
|
+
var routes = [];
|
|
112
|
+
var keys = Object.keys(config.routes);
|
|
113
|
+
for (var i = 0; i < keys.length; i++) {
|
|
114
|
+
routes.push({ pattern: keys[i], handler: config.routes[keys[i]] });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
var currentPath = '/';
|
|
118
|
+
var destroyed = false;
|
|
119
|
+
|
|
120
|
+
function getPath() {
|
|
121
|
+
if (mode === 'hash') {
|
|
122
|
+
var h = window.location.hash.replace(/^#/, '');
|
|
123
|
+
return h || '/';
|
|
124
|
+
}
|
|
125
|
+
var p = window.location.pathname;
|
|
126
|
+
if (base !== '/' && p.indexOf(base) === 0) {
|
|
127
|
+
p = p.substring(base.length) || '/';
|
|
128
|
+
}
|
|
129
|
+
var s = window.location.search || '';
|
|
130
|
+
return p + s;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function handleRoute(toRaw, opts) {
|
|
134
|
+
if (destroyed) return;
|
|
135
|
+
var fromPath = currentPath;
|
|
136
|
+
var toPath = normalizePath(toRaw);
|
|
137
|
+
|
|
138
|
+
// before guard
|
|
139
|
+
if (config.before) {
|
|
140
|
+
var result = config.before(toPath, fromPath);
|
|
141
|
+
if (result === false) return;
|
|
142
|
+
if (typeof result === 'string') {
|
|
143
|
+
toPath = normalizePath(result);
|
|
144
|
+
toRaw = result;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
currentPath = toPath;
|
|
149
|
+
|
|
150
|
+
// match route
|
|
151
|
+
var m = matchRoute(routes, toRaw);
|
|
152
|
+
if (m) {
|
|
153
|
+
var rendered = m.handler(m.params);
|
|
154
|
+
if (rendered != null && target) {
|
|
155
|
+
bw.DOM(target, rendered);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// pub/sub
|
|
160
|
+
var query = parseQuery(toRaw);
|
|
161
|
+
bw.pub('bw:route', {
|
|
162
|
+
path: toPath,
|
|
163
|
+
params: m ? m.params : {},
|
|
164
|
+
query: query,
|
|
165
|
+
from: fromPath
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// after hook
|
|
169
|
+
if (config.after) config.after(toPath, fromPath);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function navigate(path, opts) {
|
|
173
|
+
if (destroyed) return;
|
|
174
|
+
opts = opts || {};
|
|
175
|
+
if (mode === 'hash') {
|
|
176
|
+
if (opts.replace) {
|
|
177
|
+
var loc = window.location;
|
|
178
|
+
loc.replace(loc.pathname + loc.search + '#' + path);
|
|
179
|
+
} else {
|
|
180
|
+
window.location.hash = path;
|
|
181
|
+
}
|
|
182
|
+
// hashchange listener will fire handleRoute; but if same hash, trigger manually
|
|
183
|
+
var currentHash = window.location.hash.replace(/^#/, '') || '/';
|
|
184
|
+
if (normalizePath(currentHash) === normalizePath(path)) {
|
|
185
|
+
handleRoute(path, opts);
|
|
186
|
+
}
|
|
187
|
+
} else {
|
|
188
|
+
var url = (base === '/' ? '' : base) + path;
|
|
189
|
+
if (opts.replace) {
|
|
190
|
+
window.history.replaceState(null, '', url);
|
|
191
|
+
} else {
|
|
192
|
+
window.history.pushState(null, '', url);
|
|
193
|
+
}
|
|
194
|
+
handleRoute(path, opts);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function onHashChange() {
|
|
199
|
+
if (destroyed) return;
|
|
200
|
+
handleRoute(getPath());
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function onPopState() {
|
|
204
|
+
if (destroyed) return;
|
|
205
|
+
handleRoute(getPath());
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// listen
|
|
209
|
+
if (mode === 'hash') {
|
|
210
|
+
window.addEventListener('hashchange', onHashChange);
|
|
211
|
+
} else {
|
|
212
|
+
window.addEventListener('popstate', onPopState);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// initial render
|
|
216
|
+
handleRoute(getPath());
|
|
217
|
+
|
|
218
|
+
var routerObj = {
|
|
219
|
+
navigate: navigate,
|
|
220
|
+
current: function() {
|
|
221
|
+
var raw = getPath();
|
|
222
|
+
var m = matchRoute(routes, raw);
|
|
223
|
+
return {
|
|
224
|
+
path: currentPath,
|
|
225
|
+
params: m ? m.params : {},
|
|
226
|
+
query: parseQuery(raw)
|
|
227
|
+
};
|
|
228
|
+
},
|
|
229
|
+
destroy: function() {
|
|
230
|
+
destroyed = true;
|
|
231
|
+
if (mode === 'hash') {
|
|
232
|
+
window.removeEventListener('hashchange', onHashChange);
|
|
233
|
+
} else {
|
|
234
|
+
window.removeEventListener('popstate', onPopState);
|
|
235
|
+
}
|
|
236
|
+
if (_activeRouter === routerObj) _activeRouter = null;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
_activeRouter = routerObj;
|
|
241
|
+
return routerObj;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
bw.navigate = function(path, opts) {
|
|
245
|
+
if (_activeRouter) {
|
|
246
|
+
_activeRouter.navigate(path, opts);
|
|
247
|
+
} else {
|
|
248
|
+
if (typeof console !== 'undefined' && console.warn) {
|
|
249
|
+
console.warn('bw.navigate: no active router');
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
bw.link = function(path, content, attrs) {
|
|
255
|
+
var a = {};
|
|
256
|
+
if (attrs) {
|
|
257
|
+
var keys = Object.keys(attrs);
|
|
258
|
+
for (var i = 0; i < keys.length; i++) a[keys[i]] = attrs[keys[i]];
|
|
259
|
+
}
|
|
260
|
+
if (_activeRouter) {
|
|
261
|
+
// determine href based on mode -- check hash by looking at current location
|
|
262
|
+
var isHash = window.location.hash !== undefined; // always true, but we default hash
|
|
263
|
+
a.href = '#' + path;
|
|
264
|
+
} else {
|
|
265
|
+
a.href = path;
|
|
266
|
+
}
|
|
267
|
+
a.onclick = function(e) {
|
|
268
|
+
e.preventDefault();
|
|
269
|
+
bw.navigate(path);
|
|
270
|
+
};
|
|
271
|
+
return { t: 'a', a: a, c: content };
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// expose for testing: internal helpers
|
|
275
|
+
bw._router = {
|
|
276
|
+
matchRoute: matchRoute,
|
|
277
|
+
normalizePath: normalizePath,
|
|
278
|
+
parseQuery: parseQuery,
|
|
279
|
+
getActiveRouter: function() { return _activeRouter; },
|
|
280
|
+
resetActiveRouter: function() { _activeRouter = null; }
|
|
281
|
+
};
|
|
282
|
+
}
|
package/src/bitwrench-styles.js
CHANGED
|
@@ -108,10 +108,10 @@ export var ELEVATION_PRESETS = {
|
|
|
108
108
|
xl: '0 4px 12px rgba(0,0,0,0.12)'
|
|
109
109
|
},
|
|
110
110
|
md: {
|
|
111
|
-
sm: '0 1px 3px rgba(0,0,0,0.
|
|
112
|
-
md: '0
|
|
113
|
-
lg: '0 4px
|
|
114
|
-
xl: '0 8px
|
|
111
|
+
sm: '0 1px 3px rgba(0,0,0,0.10), 0 1px 2px rgba(0,0,0,0.06)',
|
|
112
|
+
md: '0 4px 6px rgba(0,0,0,0.10), 0 2px 4px rgba(0,0,0,0.06)',
|
|
113
|
+
lg: '0 10px 15px rgba(0,0,0,0.12), 0 4px 6px rgba(0,0,0,0.08)',
|
|
114
|
+
xl: '0 20px 25px rgba(0,0,0,0.15), 0 8px 10px rgba(0,0,0,0.10)'
|
|
115
115
|
},
|
|
116
116
|
lg: {
|
|
117
117
|
sm: '0 2px 4px rgba(0,0,0,0.10)',
|
|
@@ -305,6 +305,9 @@ function generateCards(scope, palette, layout) {
|
|
|
305
305
|
rules[_sx(scope, '.bw_card:hover')] = {
|
|
306
306
|
'box-shadow': elev.md
|
|
307
307
|
};
|
|
308
|
+
rules[_sx(scope, '.bw_card_hoverable')] = {
|
|
309
|
+
'transition': 'box-shadow ' + motion.slow + ' ' + motion.easing + ', transform ' + motion.slow + ' ' + motion.easing
|
|
310
|
+
};
|
|
308
311
|
rules[_sx(scope, '.bw_card_hoverable:hover')] = {
|
|
309
312
|
'box-shadow': elev.lg
|
|
310
313
|
};
|
|
@@ -405,7 +408,8 @@ function generateNavigation(scope, palette, layout) {
|
|
|
405
408
|
};
|
|
406
409
|
rules[_sx(scope, '.bw_navbar_nav .bw_nav_link')] = {
|
|
407
410
|
'color': palette.secondary.base,
|
|
408
|
-
'border-radius': layout.radius.btn
|
|
411
|
+
'border-radius': layout.radius.btn,
|
|
412
|
+
'transition': 'color ' + layout.motion.fast + ' ' + layout.motion.easing + ', background-color ' + layout.motion.fast + ' ' + layout.motion.easing
|
|
409
413
|
};
|
|
410
414
|
rules[_sx(scope, '.bw_navbar_nav .bw_nav_link:hover')] = {
|
|
411
415
|
'color': palette.dark.base,
|
|
@@ -568,15 +572,18 @@ function generatePagination(scope, palette, layout) {
|
|
|
568
572
|
return rules;
|
|
569
573
|
}
|
|
570
574
|
|
|
571
|
-
function generateProgress(scope, palette) {
|
|
575
|
+
function generateProgress(scope, palette, layout) {
|
|
572
576
|
var rules = {};
|
|
577
|
+
var rd = layout ? layout.radius : { badge: '.375rem' };
|
|
573
578
|
rules[_sx(scope, '.bw_progress')] = {
|
|
574
579
|
'background-color': palette.surfaceAlt,
|
|
580
|
+
'border-radius': rd.badge,
|
|
575
581
|
'box-shadow': 'inset 0 1px 2px rgba(0,0,0,.1)'
|
|
576
582
|
};
|
|
577
583
|
rules[_sx(scope, '.bw_progress_bar')] = {
|
|
578
584
|
'color': palette.primary.textOn,
|
|
579
585
|
'background-color': palette.primary.base,
|
|
586
|
+
'border-radius': 'inherit',
|
|
580
587
|
'box-shadow': 'inset 0 -1px 0 rgba(0,0,0,.15)'
|
|
581
588
|
};
|
|
582
589
|
// Variant progress bar colors handled by palette class
|
|
@@ -704,7 +711,8 @@ function generateCarouselThemed(scope, palette) {
|
|
|
704
711
|
};
|
|
705
712
|
rules[_sx(scope, '.bw_carousel_control')] = {
|
|
706
713
|
'background-color': palette.dark.base,
|
|
707
|
-
'color': palette.dark.textOn
|
|
714
|
+
'color': palette.dark.textOn,
|
|
715
|
+
'transition': 'background-color 0.15s ease-out'
|
|
708
716
|
};
|
|
709
717
|
rules[_sx(scope, '.bw_carousel_control:hover')] = {
|
|
710
718
|
'background-color': palette.dark.hover
|
|
@@ -718,9 +726,11 @@ function generateCarouselThemed(scope, palette) {
|
|
|
718
726
|
|
|
719
727
|
function generateModalThemed(scope, palette, layout) {
|
|
720
728
|
var rules = {};
|
|
729
|
+
var rd = layout ? layout.radius : { card: '8px' };
|
|
721
730
|
rules[_sx(scope, '.bw_modal_content')] = {
|
|
722
731
|
'background-color': palette.surface || '#fff',
|
|
723
732
|
'border-color': palette.light.border,
|
|
733
|
+
'border-radius': rd.card,
|
|
724
734
|
'box-shadow': layout.elevation.lg
|
|
725
735
|
};
|
|
726
736
|
rules[_sx(scope, '.bw_modal_header')] = {
|
|
@@ -737,9 +747,11 @@ function generateModalThemed(scope, palette, layout) {
|
|
|
737
747
|
|
|
738
748
|
function generateToastThemed(scope, palette, layout) {
|
|
739
749
|
var rules = {};
|
|
750
|
+
var rd = layout ? layout.radius : { card: '8px' };
|
|
740
751
|
rules[_sx(scope, '.bw_toast')] = {
|
|
741
752
|
'background-color': palette.surface || '#fff',
|
|
742
753
|
'border-color': palette.light.border,
|
|
754
|
+
'border-radius': rd.card,
|
|
743
755
|
'box-shadow': layout.elevation.lg
|
|
744
756
|
};
|
|
745
757
|
rules[_sx(scope, '.bw_toast_header')] = {
|
|
@@ -751,9 +763,11 @@ function generateToastThemed(scope, palette, layout) {
|
|
|
751
763
|
|
|
752
764
|
function generateDropdownThemed(scope, palette, layout) {
|
|
753
765
|
var rules = {};
|
|
766
|
+
var rd = layout ? layout.radius : { card: '8px' };
|
|
754
767
|
rules[_sx(scope, '.bw_dropdown_menu')] = {
|
|
755
768
|
'background-color': palette.surface || '#fff',
|
|
756
769
|
'border-color': palette.light.border,
|
|
770
|
+
'border-radius': rd.card,
|
|
757
771
|
'box-shadow': layout.elevation.md
|
|
758
772
|
};
|
|
759
773
|
rules[_sx(scope, '.bw_dropdown_item')] = {
|
|
@@ -786,6 +800,10 @@ function generateSwitchThemed(scope, palette) {
|
|
|
786
800
|
rules[_sx(scope, '.bw_form_switch .bw_switch_input:focus')] = {
|
|
787
801
|
'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
|
|
788
802
|
};
|
|
803
|
+
rules[_sx(scope, '.bw_form_switch .bw_switch_input:focus-visible')] = {
|
|
804
|
+
'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus,
|
|
805
|
+
'outline': 'none'
|
|
806
|
+
};
|
|
789
807
|
return rules;
|
|
790
808
|
}
|
|
791
809
|
|
|
@@ -849,12 +867,14 @@ function generateStepperThemed(scope, palette) {
|
|
|
849
867
|
return rules;
|
|
850
868
|
}
|
|
851
869
|
|
|
852
|
-
function generateChipInputThemed(scope, palette) {
|
|
870
|
+
function generateChipInputThemed(scope, palette, layout) {
|
|
853
871
|
var rules = {};
|
|
872
|
+
var rd = layout ? layout.radius : { input: '6px' };
|
|
854
873
|
rules[_sx(scope, '.bw_chip_input')] = {
|
|
855
874
|
'border-color': palette.light.border,
|
|
856
875
|
'background-color': palette.surface || '#fff',
|
|
857
|
-
'color': palette.dark.base
|
|
876
|
+
'color': palette.dark.base,
|
|
877
|
+
'border-radius': rd.input
|
|
858
878
|
};
|
|
859
879
|
rules[_sx(scope, '.bw_chip_input:focus-within')] = {
|
|
860
880
|
'border-color': palette.primary.base,
|
|
@@ -1139,7 +1159,7 @@ export function generateThemedCSS(scopeName, palette, layout) {
|
|
|
1139
1159
|
generateTabs(scopeName, palette, layout),
|
|
1140
1160
|
generateListGroups(scopeName, palette, layout),
|
|
1141
1161
|
generatePagination(scopeName, palette, layout),
|
|
1142
|
-
generateProgress(scopeName, palette),
|
|
1162
|
+
generateProgress(scopeName, palette, layout),
|
|
1143
1163
|
generateBreadcrumbThemed(scopeName, palette, layout),
|
|
1144
1164
|
generateCloseButtonThemed(scopeName, palette),
|
|
1145
1165
|
generateSectionsThemed(scopeName, palette),
|
|
@@ -1153,7 +1173,7 @@ export function generateThemedCSS(scopeName, palette, layout) {
|
|
|
1153
1173
|
generateStatCardThemed(scopeName, palette, layout),
|
|
1154
1174
|
generateTimelineThemed(scopeName, palette),
|
|
1155
1175
|
generateStepperThemed(scopeName, palette),
|
|
1156
|
-
generateChipInputThemed(scopeName, palette),
|
|
1176
|
+
generateChipInputThemed(scopeName, palette, layout),
|
|
1157
1177
|
generateFileUploadThemed(scopeName, palette, layout),
|
|
1158
1178
|
generateRangeThemed(scopeName, palette),
|
|
1159
1179
|
generateSearchThemed(scopeName, palette, layout),
|
|
@@ -1301,7 +1321,7 @@ var structuralRules = {
|
|
|
1301
1321
|
'.bw_card_text': { 'margin-bottom': '0', 'font-size': '0.9375rem', 'line-height': '1.6' },
|
|
1302
1322
|
'.bw_card_header': { 'margin-bottom': '0', 'font-weight': '600', 'font-size': '0.875rem' },
|
|
1303
1323
|
'.bw_card_footer': { 'font-size': '0.875rem' },
|
|
1304
|
-
'.bw_card_hoverable': {
|
|
1324
|
+
'.bw_card_hoverable': {},
|
|
1305
1325
|
'.bw_card_hoverable:hover': { 'transform': 'translateY(-4px)' },
|
|
1306
1326
|
'.bw_card_img_top': { 'width': '100%' },
|
|
1307
1327
|
'.bw_card_img_bottom': { 'width': '100%' },
|
|
@@ -1316,7 +1336,8 @@ var structuralRules = {
|
|
|
1316
1336
|
'display': 'block', 'width': '100%',
|
|
1317
1337
|
'font-size': '0.9375rem', 'font-weight': '400', 'line-height': '1.5',
|
|
1318
1338
|
'background-clip': 'padding-box', 'appearance': 'none',
|
|
1319
|
-
'border': '1px solid transparent', 'font-family': 'inherit'
|
|
1339
|
+
'border': '1px solid transparent', 'font-family': 'inherit',
|
|
1340
|
+
'transition': 'border-color 0.15s ease-out, box-shadow 0.15s ease-out'
|
|
1320
1341
|
},
|
|
1321
1342
|
'.bw_form_control:focus': { 'outline': '2px solid currentColor', 'outline-offset': '-1px' },
|
|
1322
1343
|
'.bw_form_control::placeholder': { 'opacity': '1' },
|
|
@@ -1443,6 +1464,7 @@ var structuralRules = {
|
|
|
1443
1464
|
'text-decoration': 'none', 'cursor': 'pointer',
|
|
1444
1465
|
'border': 'none', 'background': 'transparent', 'font-family': 'inherit'
|
|
1445
1466
|
},
|
|
1467
|
+
'.bw_nav_link:focus-visible': { 'outline': '2px solid currentColor', 'outline-offset': '-2px' },
|
|
1446
1468
|
'.bw_nav_tabs .bw_nav_link': { 'border': 'none', 'border-bottom': '2px solid transparent', 'border-radius': '0', 'background-color': 'transparent' },
|
|
1447
1469
|
'.bw_nav_vertical': { 'flex-direction': 'column' },
|
|
1448
1470
|
'.bw_tab_content': { 'padding': '1.25rem 0' },
|
|
@@ -1560,9 +1582,11 @@ var structuralRules = {
|
|
|
1560
1582
|
'display': 'inline-flex', 'align-items': 'center', 'justify-content': 'center',
|
|
1561
1583
|
'width': '1.5rem', 'height': '1.5rem', 'padding': '0',
|
|
1562
1584
|
'font-size': '1.25rem', 'font-weight': '700', 'line-height': '1',
|
|
1563
|
-
'background': 'transparent', 'border': '0', 'border-radius': '0.25rem', 'cursor': 'pointer'
|
|
1585
|
+
'background': 'transparent', 'border': '0', 'border-radius': '0.25rem', 'cursor': 'pointer',
|
|
1586
|
+
'transition': 'opacity 0.15s ease-out'
|
|
1564
1587
|
},
|
|
1565
|
-
'.bw_close:hover': { 'opacity': '0.75' }
|
|
1588
|
+
'.bw_close:hover': { 'opacity': '0.75' },
|
|
1589
|
+
'.bw_close:focus-visible': { 'outline': '2px solid currentColor', 'outline-offset': '2px' }
|
|
1566
1590
|
},
|
|
1567
1591
|
|
|
1568
1592
|
// ---- Stacks ----
|
|
@@ -1644,7 +1668,8 @@ var structuralRules = {
|
|
|
1644
1668
|
'flex-shrink': '0', 'width': '1.25rem', 'height': '1.25rem', 'margin-left': 'auto',
|
|
1645
1669
|
'content': '""',
|
|
1646
1670
|
'background-image': "url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\")",
|
|
1647
|
-
'background-repeat': 'no-repeat', 'background-size': '1.25rem'
|
|
1671
|
+
'background-repeat': 'no-repeat', 'background-size': '1.25rem',
|
|
1672
|
+
'transition': 'transform 0.2s ease-out'
|
|
1648
1673
|
},
|
|
1649
1674
|
'.bw_accordion_button:not(.bw_collapsed)::after': { 'transform': 'rotate(-180deg)' },
|
|
1650
1675
|
'.bw_accordion_body': { 'padding': '1rem 1.25rem' },
|
|
@@ -1669,6 +1694,7 @@ var structuralRules = {
|
|
|
1669
1694
|
'z-index': '2', 'padding': '0'
|
|
1670
1695
|
},
|
|
1671
1696
|
'.bw_carousel_control img': { 'width': '20px', 'height': '20px', 'pointer-events': 'none' },
|
|
1697
|
+
'.bw_carousel_control:focus-visible': { 'outline': '2px solid currentColor', 'outline-offset': '2px' },
|
|
1672
1698
|
'.bw_carousel_control_prev': { 'left': '10px' },
|
|
1673
1699
|
'.bw_carousel_control_next': { 'right': '10px' },
|
|
1674
1700
|
'.bw_carousel_indicators': {
|
|
@@ -1688,12 +1714,14 @@ var structuralRules = {
|
|
|
1688
1714
|
'display': 'flex', 'align-items': 'center', 'justify-content': 'center',
|
|
1689
1715
|
'position': 'fixed', 'top': '0', 'left': '0', 'width': '100%', 'height': '100%',
|
|
1690
1716
|
'z-index': '1050', 'overflow-x': 'hidden', 'overflow-y': 'auto',
|
|
1691
|
-
'opacity': '0', 'visibility': 'hidden', 'pointer-events': 'none'
|
|
1717
|
+
'opacity': '0', 'visibility': 'hidden', 'pointer-events': 'none',
|
|
1718
|
+
'transition': 'opacity 0.2s ease-out, visibility 0.2s ease-out'
|
|
1692
1719
|
},
|
|
1693
1720
|
'.bw_modal.bw_modal_show': { 'opacity': '1', 'visibility': 'visible', 'pointer-events': 'auto' },
|
|
1694
1721
|
'.bw_modal_dialog': {
|
|
1695
1722
|
'position': 'relative', 'width': 'calc(100% - 1rem)', 'max-width': '500px', 'margin': '1.75rem auto',
|
|
1696
|
-
'pointer-events': 'none'
|
|
1723
|
+
'pointer-events': 'none', 'transform': 'translateY(-16px)',
|
|
1724
|
+
'transition': 'transform 0.2s ease-out'
|
|
1697
1725
|
},
|
|
1698
1726
|
'.bw_modal.bw_modal_show .bw_modal_dialog': { 'transform': 'translateY(0)' },
|
|
1699
1727
|
'.bw_modal_sm': { 'max-width': '300px' },
|
|
@@ -1723,10 +1751,11 @@ var structuralRules = {
|
|
|
1723
1751
|
'.bw_toast_container.bw_toast_bottom_center': { 'bottom': '0', 'left': '50%', 'transform': 'translateX(-50%)' },
|
|
1724
1752
|
'.bw_toast': {
|
|
1725
1753
|
'pointer-events': 'auto', 'width': '350px', 'max-width': 'calc(100vw - 2rem)', 'background-clip': 'padding-box',
|
|
1726
|
-
'opacity': '0'
|
|
1754
|
+
'opacity': '0', 'transform': 'translateY(-8px)',
|
|
1755
|
+
'transition': 'opacity 0.2s ease-out, transform 0.2s ease-out'
|
|
1727
1756
|
},
|
|
1728
1757
|
'.bw_toast.bw_toast_show': { 'opacity': '1', 'transform': 'translateY(0)' },
|
|
1729
|
-
'.bw_toast.bw_toast_hiding': { 'opacity': '0' },
|
|
1758
|
+
'.bw_toast.bw_toast_hiding': { 'opacity': '0', 'transform': 'translateY(-8px)' },
|
|
1730
1759
|
'.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
1760
|
'.bw_toast_body': { 'padding': '0.5rem 0.75rem', 'font-size': '0.9375rem' }
|
|
1732
1761
|
},
|
|
@@ -1743,9 +1772,11 @@ var structuralRules = {
|
|
|
1743
1772
|
'position': 'absolute', 'top': '100%', 'left': '0', 'z-index': '1000', 'display': 'block',
|
|
1744
1773
|
'min-width': '10rem', 'padding': '0.5rem 0', 'margin': '0.125rem 0 0',
|
|
1745
1774
|
'background-clip': 'padding-box', 'border': '1px solid transparent',
|
|
1746
|
-
'opacity': '0', 'visibility': 'hidden', 'pointer-events': 'none'
|
|
1775
|
+
'opacity': '0', 'visibility': 'hidden', 'pointer-events': 'none',
|
|
1776
|
+
'transform': 'translateY(-4px)',
|
|
1777
|
+
'transition': 'opacity 0.15s ease-out, transform 0.15s ease-out, visibility 0.15s ease-out'
|
|
1747
1778
|
},
|
|
1748
|
-
'.bw_dropdown_menu.bw_dropdown_show': { 'opacity': '1', 'visibility': 'visible', 'pointer-events': 'auto' },
|
|
1779
|
+
'.bw_dropdown_menu.bw_dropdown_show': { 'opacity': '1', 'visibility': 'visible', 'pointer-events': 'auto', 'transform': 'translateY(0)' },
|
|
1749
1780
|
'.bw_dropdown_menu_end': { 'left': 'auto', 'right': '0' },
|
|
1750
1781
|
'.bw_dropdown_item': {
|
|
1751
1782
|
'display': 'block', 'width': '100%', 'padding': '0.4rem 1rem', 'clear': 'both',
|
|
@@ -1764,7 +1795,8 @@ var structuralRules = {
|
|
|
1764
1795
|
'appearance': 'none',
|
|
1765
1796
|
'background-image': "url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba(255,255,255,1)'/%3e%3c/svg%3e\")",
|
|
1766
1797
|
'background-position': 'left center', 'background-repeat': 'no-repeat',
|
|
1767
|
-
'background-size': 'contain', 'cursor': 'pointer'
|
|
1798
|
+
'background-size': 'contain', 'cursor': 'pointer',
|
|
1799
|
+
'transition': 'background-color 0.15s ease-out, background-position 0.15s ease-out, border-color 0.15s ease-out'
|
|
1768
1800
|
},
|
|
1769
1801
|
'.bw_form_switch .bw_switch_input:checked': { 'background-position': 'right center' },
|
|
1770
1802
|
'.bw_form_switch .bw_switch_input:disabled': { 'opacity': '0.5', 'cursor': 'not-allowed' }
|
|
@@ -1798,9 +1830,7 @@ var structuralRules = {
|
|
|
1798
1830
|
'.bw_stat_card': {
|
|
1799
1831
|
'padding': '1.25rem',
|
|
1800
1832
|
'border-left': '4px solid transparent',
|
|
1801
|
-
'
|
|
1802
|
-
'background-color': 'inherit',
|
|
1803
|
-
'transition': 'transform 0.15s ease'
|
|
1833
|
+
'background-color': 'inherit'
|
|
1804
1834
|
},
|
|
1805
1835
|
'.bw_stat_card:hover': { 'transform': 'translateY(-1px)' },
|
|
1806
1836
|
'.bw_stat_icon': { 'font-size': '1.5rem', 'margin-bottom': '0.5rem' },
|
|
@@ -1860,7 +1890,8 @@ var structuralRules = {
|
|
|
1860
1890
|
'width': '1.5rem', 'height': '1.5rem',
|
|
1861
1891
|
'border': 'none', 'background': 'none',
|
|
1862
1892
|
'font-size': '1.25rem', 'cursor': 'pointer', 'padding': '0', 'border-radius': '50%'
|
|
1863
|
-
}
|
|
1893
|
+
},
|
|
1894
|
+
'.bw_search_clear:focus-visible': { 'outline': '2px solid currentColor', 'outline-offset': '2px' }
|
|
1864
1895
|
},
|
|
1865
1896
|
|
|
1866
1897
|
// ---- Range ----
|
|
@@ -1952,6 +1983,7 @@ var structuralRules = {
|
|
|
1952
1983
|
'width': '1rem', 'height': '1rem', 'border': 'none', 'background': 'none',
|
|
1953
1984
|
'font-size': '0.875rem', 'cursor': 'pointer', 'padding': '0', 'border-radius': '50%'
|
|
1954
1985
|
},
|
|
1986
|
+
'.bw_chip_remove:focus-visible': { 'outline': '2px solid currentColor', 'outline-offset': '1px' },
|
|
1955
1987
|
'.bw_chip_field': { 'flex': '1', 'min-width': '80px', 'border': 'none', 'outline': 'none', 'font-size': '0.875rem', 'padding': '0.125rem 0', 'background': 'transparent' }
|
|
1956
1988
|
},
|
|
1957
1989
|
|
package/src/bitwrench.js
CHANGED
|
@@ -3566,6 +3566,12 @@ bw.getAllComponents = function() {
|
|
|
3566
3566
|
return new Map(bw._componentRegistry);
|
|
3567
3567
|
};
|
|
3568
3568
|
|
|
3569
|
+
// =========================================================================
|
|
3570
|
+
// Import and register router
|
|
3571
|
+
// =========================================================================
|
|
3572
|
+
import { initRouter } from './bitwrench-router.js';
|
|
3573
|
+
initRouter(bw);
|
|
3574
|
+
|
|
3569
3575
|
// =========================================================================
|
|
3570
3576
|
// Import and register all components
|
|
3571
3577
|
// =========================================================================
|