@webority/theme 0.69.0 → 0.70.1
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
CHANGED
|
@@ -122,6 +122,25 @@ after the components. Dark mode is emitted under `[data-theme=dark]`, `[data-bs-
|
|
|
122
122
|
`data-theme=auto` media query. Contrast of every brand text and surface pair is held at 4.5:1 by check-contrast.
|
|
123
123
|
`_brand-signal.scss` owns brand values only; no component CSS.
|
|
124
124
|
|
|
125
|
+
## Runtime brand from a product's token file (opt-in)
|
|
126
|
+
|
|
127
|
+
A product's look can be applied to the precompiled theme at runtime, which is how the hosted showcase shows
|
|
128
|
+
every component in a product's design language.
|
|
129
|
+
|
|
130
|
+
- `webority-theme-export <compiled.css>... --product <name> --out tokens.json` (a bin of this package) writes
|
|
131
|
+
the token file, format `webority-theme-tokens/1`: `{ format, product, light, dark, bootstrapDark }`, each a
|
|
132
|
+
map of custom property to value. It reads the product's compiled CSS, not its SCSS, because Bootstrap's rgb
|
|
133
|
+
triplets and subtle and emphasis mixes only exist after compilation. `light` is the top-level `:root`,
|
|
134
|
+
`dark` the theme's `:root[data-theme=dark]` rule, `bootstrapDark` Bootstrap's `[data-bs-theme=dark]` rule.
|
|
135
|
+
- `dist/webority-runtime-brand.css` (export `@webority/theme/css/runtime-brand`, source
|
|
136
|
+
`scss/_runtime-brand.scss`) re-points the few component rules Bootstrap compiles from `$primary` as literals
|
|
137
|
+
(primary buttons, nav pills, pagination, list group, progress, range thumb, mouse focus border, `.link-primary`
|
|
138
|
+
hover, `.table-primary`) at `--bs-primary`. It holds no colour of its own (check-theme-exports asserts it).
|
|
139
|
+
- Load order: the theme, then the runtime brand layer, then the token file's values on `:root`, under the dark
|
|
140
|
+
selectors for `dark`, and under `[data-bs-theme=dark]` for `bootstrapDark`.
|
|
141
|
+
- Each product serves its file at `/theme/tokens.json` with `Access-Control-Allow-Origin` for the showcase host.
|
|
142
|
+
- A font the token file names renders only when the page has its face: the theme's own families do.
|
|
143
|
+
|
|
125
144
|
## Dark mode
|
|
126
145
|
|
|
127
146
|
The theme ships with two built-in dark-mode support patterns:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.btn-primary{--bs-btn-bg: var(--bs-primary);--bs-btn-border-color: var(--bs-primary);--bs-btn-disabled-bg: var(--bs-primary);--bs-btn-disabled-border-color: var(--bs-primary);--bs-btn-focus-shadow-rgb: var(--bs-primary-rgb)}.btn-outline-primary{--bs-btn-focus-shadow-rgb: var(--bs-primary-rgb)}.nav-pills{--bs-nav-pills-link-active-bg: var(--bs-primary)}.pagination{--bs-pagination-active-bg: var(--bs-primary);--bs-pagination-active-border-color: var(--bs-primary)}.list-group{--bs-list-group-active-bg: var(--bs-primary);--bs-list-group-active-border-color: var(--bs-primary)}.progress,.progress-stacked{--bs-progress-bar-bg: var(--bs-primary)}.form-check-input:focus:not(:focus-visible):not(:checked):not([type=checkbox]:indeterminate){border-color:color-mix(in srgb, var(--bs-primary) 50%, #fff)}.form-range::-webkit-slider-thumb{background-color:var(--bs-primary)}.form-range::-webkit-slider-thumb:active{background-color:color-mix(in srgb, var(--bs-primary) 30%, #fff)}.form-range::-moz-range-thumb{background-color:var(--bs-primary)}.form-range::-moz-range-thumb:active{background-color:color-mix(in srgb, var(--bs-primary) 30%, #fff)}.link-primary:hover,.link-primary:focus{color:color-mix(in srgb, color-mix(in srgb, var(--bs-primary) 80%, #000) calc(var(--bs-link-opacity, 1) * 100%), transparent) !important;text-decoration-color:color-mix(in srgb, color-mix(in srgb, var(--bs-primary) 80%, #000) calc(var(--bs-link-underline-opacity, 1) * 100%), transparent) !important}.table-primary{--wui-table-primary-bg: color-mix(in srgb, var(--bs-primary) 20%, #fff);--bs-table-bg: var(--wui-table-primary-bg);--bs-table-border-color: color-mix(in srgb, #000 20%, var(--wui-table-primary-bg));--bs-table-striped-bg: color-mix(in srgb, #000 5%, var(--wui-table-primary-bg));--bs-table-active-bg: color-mix(in srgb, #000 10%, var(--wui-table-primary-bg));--bs-table-hover-bg: color-mix(in srgb, #000 7.5%, var(--wui-table-primary-bg))}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{readFileSync as e,writeFileSync as t}from"node:fs";var n=`webority-theme-tokens/1`,r=[`--wui-primary`,`--bs-primary`,`--bs-primary-rgb`,`--bs-link-color-rgb`,`--bs-body-font-family`];function i(e){console.error(`webority-theme-export: ${e}`),console.error(`usage: webority-theme-export <compiled.css>... --product <name> [--out <tokens.json>]`),process.exit(2)}function a(e){let t=[],n,r;for(let a=0;a<e.length;a++)e[a]===`--product`?n=e[++a]:e[a]===`--out`?r=e[++a]:e[a].startsWith(`--`)?i(`unknown option ${e[a]}`):t.push(e[a]);return t.length===0&&i(`no compiled CSS file given`),(!n||!/^[a-z0-9-]+$/.test(n))&&i(`--product must be the product's lowercase name`),{files:t,product:n,out:r}}function o(e,t){let n=[],r=0,i=null,a=0;for(let o=0;o<e.length;o++){let s=e[o];i?s===`\\`?o++:s===i&&(i=null):s===`"`||s===`'`?i=s:s===`(`||s===`[`?r++:s===`)`||s===`]`?r--:s===t&&r===0&&(n.push(e.slice(a,o)),a=o+1)}return n.push(e.slice(a)),n}function s(e){let t=[],n=0,r=null,i=0,a=-1;for(let s=0;s<e.length;s++){let l=e[s];if(r)l===`\\`?s++:l===r&&(r=null);else if(l===`"`||l===`'`)r=l;else if(l===`{`)n===0&&(a=s),n++;else if(l===`}`){if(n--,n===0){let n=e.slice(i,a).trim();n.startsWith(`@`)||t.push({selectors:o(n,`,`).map(c),body:e.slice(a+1,s)}),i=s+1}}else l===`;`&&n===0&&(i=s+1)}return t}function c(e){return e.trim().replace(/\s+/g,` `).replace(/["']/g,``)}var l=new Set([`:root`,`[data-bs-theme=light]`,`:root[data-bs-theme=light]`,`:root[data-theme=light]`]),u=new Set([`:root[data-theme=dark]`,`:root[data-bs-theme=dark]`]),d=new Set([`[data-bs-theme=dark]`]);function f(e){let t=[];for(let n of o(e,`;`)){let e=n.indexOf(`:`);if(e<0)continue;let r=n.slice(0,e).trim();r.startsWith(`--`)&&t.push([r,n.slice(e+1).trim().replace(/\s*!important$/,``)])}return t}var{files:p,product:m,out:h}=a(process.argv.slice(2)),g={},_={},v={};for(let t of p){let n=e(t,`utf8`).replace(/\/\*[\s\S]*?\*\//g,``);for(let e of s(n)){let t=t=>e.selectors.some(e=>t.has(e)),n=t(u)?_:t(d)?v:t(l)?g:null;if(n)for(let[t,r]of f(e.body))n[t]=r}}var y=r.filter(e=>!(e in g));y.length>0&&(console.error(`webority-theme-export: ${p.join(`, `)} declares no ${y.join(`, `)} on :root.`),console.error(`Pass the compiled stylesheet that carries the full theme, not a page or component bundle.`),process.exit(1));var b=e=>Object.fromEntries(Object.entries(e).sort(([e],[t])=>e.localeCompare(t))),x=`${JSON.stringify({format:n,product:m,light:b(g),dark:b(_),bootstrapDark:b(v)},null,2)}\n`;h?(t(h,x),process.stderr.write(`webority-theme-export: ${Object.keys(g).length} light and ${Object.keys(_).length} dark and ${Object.keys(v).length} Bootstrap dark values -> ${h}\n`)):process.stdout.write(x);export{};
|