diff --git a/modules/utils/deferredPromise.d.ts b/modules/utils/deferredPromise.d.ts deleted file mode 100644 index e69498d..0000000 --- a/modules/utils/deferredPromise.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -interface DeferredPromise extends Promise{ - resolve: (value: T) => void - reject: (reason?: any) => void -} \ No newline at end of file diff --git a/modules/utils/deferredPromise.mjs b/modules/utils/deferredPromise.mjs index 5680822..b9151bb 100644 --- a/modules/utils/deferredPromise.mjs +++ b/modules/utils/deferredPromise.mjs @@ -1,5 +1,12 @@ //@ts-check -/// + +/** + * @template {any} T + * @typedef {{ + * resolve: (value: T) => void + * reject: (reason?: any) => void + * } & Promise} DeferredPromise A promise that can be resolved externally + */ /** * Returns a promise that can be resolved externally. diff --git a/modules/utils/index.mjs b/modules/utils/index.mjs index fc0048a..14b8fa9 100644 --- a/modules/utils/index.mjs +++ b/modules/utils/index.mjs @@ -39,6 +39,8 @@ import { makeEventEmitter } from "./makeEventEmitter.mjs"; import { makeFileLoader, makeFileLoadersTracker } from "./makeFileLoader.mjs"; import { makeFileSizeFetcher } from "./makeFileSizeFetcher.mjs"; import { makeSignal } from "./makeSignal.mjs"; +import { makeStyleSheet, css } from "./makeStyleSheet.mjs"; +import { makeTemplate, tmpl } from "./makeTemplate.mjs"; import { markdownToMarkup } from "./markdownToMarkup.mjs"; import { markupToDom } from "./markupToDom.mjs"; import { memoize } from "./memoize.mjs"; @@ -58,7 +60,7 @@ import { metadata, } from "./path.mjs"; import { percentFromProgress } from "./percentFromProgress.mjs"; -import { print, makeTemplate } from "./print.mjs"; +import { print, makeMiniStringTemplate } from "./print.mjs"; import { querySelectorDoc, querySelectorParent, @@ -68,6 +70,7 @@ import { retryPromise } from "./retryPromise.mjs"; import { rewriteLocalUrls } from "./rewriteLocalUrls.mjs"; import { throttle } from "./throttle.mjs"; import { today } from "./today.mjs"; +import { trackProgressWithCSS } from "./trackProgressWithCSS.mjs"; import { UnreachableCaseError } from "./UnreachableCaseError.mjs"; import { wait } from "./wait.mjs"; import { waitIfLocalHost } from "./waitIfLocalHost.mjs"; @@ -111,6 +114,10 @@ export { makeFileLoadersTracker, makeFileSizeFetcher, makeSignal, + makeStyleSheet, + css, + makeTemplate, + tmpl, markdownToMarkup, markupToDom, memoize, @@ -127,7 +134,7 @@ export { metadata, percentFromProgress, print, - makeTemplate, + makeMiniStringTemplate, querySelectorDoc, querySelectorParent, querySelectorAll, @@ -135,6 +142,7 @@ export { rewriteLocalUrls, throttle, today, + trackProgressWithCSS, UnreachableCaseError, wait, waitIfLocalHost, diff --git a/modules/utils/makeStyleSheet.mjs b/modules/utils/makeStyleSheet.mjs new file mode 100644 index 0000000..6059317 --- /dev/null +++ b/modules/utils/makeStyleSheet.mjs @@ -0,0 +1,24 @@ +//@ts-check + + +/** + * Returns a stylesheet + * @param {string} css_string + * @returns + */ +export const makeStyleSheet = (css_string) => { + const stylesheet = new CSSStyleSheet(); + stylesheet.replaceSync(css_string); + return stylesheet +} + +/** + * Convenience literal to create DOM CSSStyleSheet instances + * @param {TemplateStringsArray} strings + * @param {...any} substitutions + */ +export const css = (strings, ...substitutions) => { + const formattedString = strings.reduce((acc, curr, index) => acc + curr + (substitutions[index]||''), ''); + console.log(formattedString) + return makeStyleSheet(formattedString); +} \ No newline at end of file diff --git a/modules/utils/makeTemplate.mjs b/modules/utils/makeTemplate.mjs new file mode 100644 index 0000000..a2c04fe --- /dev/null +++ b/modules/utils/makeTemplate.mjs @@ -0,0 +1,23 @@ +//@ts-check + + +/** + * Returns a template + * @param {string} template_string + * @returns + */ +export const makeTemplate = (template_string) => { + const template = document.createElement("template") + template.innerHTML = template_string + return template +} + +/** + * Convenience literal to create DOM template elements + * @param {TemplateStringsArray} strings + * @param {...any} substitutions + */ +export const tmpl = (strings, ...substitutions) => { + const formattedString = strings.reduce((acc, curr, index) => acc + curr + (substitutions[index]||''), ''); + return makeTemplate(formattedString); +} \ No newline at end of file diff --git a/modules/utils/percentFromProgress.mjs b/modules/utils/percentFromProgress.mjs index 447cca2..2248447 100644 --- a/modules/utils/percentFromProgress.mjs +++ b/modules/utils/percentFromProgress.mjs @@ -3,8 +3,9 @@ /** * Returns a formatted percent from a given fraction. * @param {number} fraction any fractional number, e.g, 5/10 + * @param {boolean} [pad] */ -export const percentFromProgress = (fraction) => - /** @type {`${string}%`} */ (Math.round(fraction * 100) + "%"); +export const percentFromProgress = (fraction, pad = false) => + /** @type {`${string}%`} */ (Math.round(fraction * 100) + "%").padStart(pad? 3 : 0, "0"); export default percentFromProgress \ No newline at end of file diff --git a/modules/utils/print.mjs b/modules/utils/print.mjs index 8cc8d1f..5d1bdc0 100644 --- a/modules/utils/print.mjs +++ b/modules/utils/print.mjs @@ -12,8 +12,8 @@ export const print = (str, replacements) => * @param {string} str * @returns {(replacements: Record) => string} */ -export const makeTemplate = (str) => print.bind(null, str) +export const makeMiniStringTemplate = (str) => print.bind(null, str) -print.makeTemplate = makeTemplate +print.makeTemplate = makeMiniStringTemplate export default print \ No newline at end of file diff --git a/modules/utils/trackProgressWithCSS.mjs b/modules/utils/trackProgressWithCSS.mjs new file mode 100644 index 0000000..5d55465 --- /dev/null +++ b/modules/utils/trackProgressWithCSS.mjs @@ -0,0 +1,35 @@ +//@ts-check + +import { percentFromProgress } from "./percentFromProgress.mjs"; + +/** + * Returns a function that can update an HTML Element. + * The function, when called with `received` and `total`, set 3 custom css vars + * on the element, which can be used in CSS to reflect the state of the object + * @param {HTMLElement} element + */ +export const trackProgressWithCSS = (element, prefix = "load-") => { + const keyFract = `--${prefix}fraction`; + const keyProgress = `--${prefix}progress`; + const keyProgressStr = `--${prefix}progress-str`; + const classComplete = `${prefix}complete`; + /** + * @param {{received: number, total: number}} progress + */ + const setProgress = ({ received, total }) => { + const final = received == total; + const fraction = final ? 1 : received / total; + const percent = final ? "100%" : percentFromProgress(fraction, true); + console.log(keyProgress, percent); + element.style.setProperty(keyFract, `${fraction}`); + element.style.setProperty(keyProgress, percent); + element.style.setProperty(keyProgressStr, `"${percent}"`); + if (final) { + console.log("all done!", element, classComplete) + requestAnimationFrame(() => element.classList.add(classComplete)); + } + }; + return setProgress; +}; + +export default trackProgressWithCSS;