Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a7dfcc019 | ||
|
|
0c2785ca3b |
+2
-1
@@ -170,7 +170,7 @@
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
import '../px-icon.js';
|
||||
import { refreshAll } from '../px-icon.js';
|
||||
|
||||
const apSizeInput = document.getElementById('apSize');
|
||||
const apSizeVal = document.getElementById('apSizeVal');
|
||||
@@ -181,6 +181,7 @@ function applyConfig() {
|
||||
apSizeVal.textContent = ap;
|
||||
document.documentElement.style.setProperty('--pxicon-ap-size', ap + 'px');
|
||||
document.documentElement.style.setProperty('--pxicon-mode', modeSelect.value);
|
||||
refreshAll();
|
||||
}
|
||||
apSizeInput.addEventListener('input', applyConfig);
|
||||
modeSelect.addEventListener('change', applyConfig);
|
||||
|
||||
+32
-10
@@ -15,6 +15,14 @@ const DEFAULT_AP_SIZE = 8;
|
||||
const DEFAULT_MODE = 'average';
|
||||
const SUPERSAMPLE = 8; // per grid cell, for point-sample mode
|
||||
|
||||
// CSS custom properties (--pxicon-ap-size, --pxicon-mode, ...) aren't
|
||||
// observable the way DOM mutations/resizes are: MutationObserver and
|
||||
// ResizeObserver don't fire when a cascaded custom property changes.
|
||||
// Instances listen for this document-level event so config changes (e.g.
|
||||
// a page-level theme/control update) can trigger a re-check without every
|
||||
// caller needing to touch each <px-icon>'s internals.
|
||||
const REFRESH_EVENT = 'pxicon:refresh';
|
||||
|
||||
// key -> Promise<HTMLCanvasElement> (the small pre-upscale grid raster)
|
||||
const rasterCache = new Map();
|
||||
|
||||
@@ -131,12 +139,15 @@ class PxIcon extends HTMLElement {
|
||||
// e.g. a morph swapping in a different icon.
|
||||
this._observer ??= new MutationObserver(() => this._scheduleRender());
|
||||
this._observer.observe(this, { childList: true, subtree: true, attributes: true, characterData: true });
|
||||
this._refreshHandler ??= () => this._scheduleRender();
|
||||
document.addEventListener(REFRESH_EVENT, this._refreshHandler);
|
||||
this._scheduleRender();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this._observer?.disconnect();
|
||||
this._resizeObserver?.disconnect();
|
||||
document.removeEventListener(REFRESH_EVENT, this._refreshHandler);
|
||||
}
|
||||
|
||||
_upgrade() {
|
||||
@@ -181,10 +192,12 @@ class PxIcon extends HTMLElement {
|
||||
const apSize = parseFloat(cs.getPropertyValue('--pxicon-ap-size')) || DEFAULT_AP_SIZE;
|
||||
const mode = (cs.getPropertyValue('--pxicon-mode') || DEFAULT_MODE).trim();
|
||||
|
||||
const displaySize = Math.max(this.clientWidth, this.clientHeight) || 24;
|
||||
const snapped = snapToGrid(displaySize, apSize);
|
||||
const gridW = Math.max(1, Math.round(snapped / apSize));
|
||||
const gridH = gridW;
|
||||
const displayW = this.clientWidth || 24;
|
||||
const displayH = this.clientHeight || 24;
|
||||
const snappedW = snapToGrid(displayW, apSize);
|
||||
const snappedH = snapToGrid(displayH, apSize);
|
||||
const gridW = Math.max(1, Math.round(snappedW / apSize));
|
||||
const gridH = Math.max(1, Math.round(snappedH / apSize));
|
||||
|
||||
const svgMarkup = svgEl.outerHTML;
|
||||
const key = `${svgMarkup}|${mode}|${gridW}x${gridH}`;
|
||||
@@ -200,13 +213,14 @@ class PxIcon extends HTMLElement {
|
||||
const gridCanvas = await getGridRaster(svgMarkup, mode, gridW, gridH);
|
||||
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
const backingSize = Math.round(snapped * dpr);
|
||||
this._canvas.width = backingSize;
|
||||
this._canvas.height = backingSize;
|
||||
const backingW = Math.round(snappedW * dpr);
|
||||
const backingH = Math.round(snappedH * dpr);
|
||||
this._canvas.width = backingW;
|
||||
this._canvas.height = backingH;
|
||||
const ctx = this._canvas.getContext('2d');
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
ctx.clearRect(0, 0, backingSize, backingSize);
|
||||
ctx.drawImage(gridCanvas, 0, 0, backingSize, backingSize);
|
||||
ctx.clearRect(0, 0, backingW, backingH);
|
||||
ctx.drawImage(gridCanvas, 0, 0, backingW, backingH);
|
||||
|
||||
if (this._slot.isConnected) {
|
||||
// first successful raster: swap the placeholder slot for the
|
||||
@@ -219,4 +233,12 @@ class PxIcon extends HTMLElement {
|
||||
|
||||
customElements.define('px-icon', PxIcon);
|
||||
|
||||
export { PxIcon, rasterCache };
|
||||
// Call after changing a --pxicon-* custom property (e.g. on :root, or any
|
||||
// ancestor of a group of icons) to make every connected <px-icon> re-check
|
||||
// its computed config and re-render if it actually changed. Cheap to call
|
||||
// broadly: each instance's own key check skips the work if nothing did.
|
||||
function refreshAll() {
|
||||
document.dispatchEvent(new CustomEvent(REFRESH_EVENT));
|
||||
}
|
||||
|
||||
export { PxIcon, rasterCache, refreshAll };
|
||||
|
||||
Reference in New Issue
Block a user