add autoloader prototype

autoload
Cory LaViska 2023-02-22 14:18:04 -05:00
rodzic a4131caeda
commit a32488baeb
6 zmienionych plików z 83 dodań i 1 usunięć

Wyświetl plik

@ -9,6 +9,9 @@
"atrule",
"autocorrect",
"autofix",
"autoload",
"autoloader",
"autoloading",
"autoplay",
"bezier",
"boxicons",

Wyświetl plik

@ -8,6 +8,8 @@ New versions of Shoelace are released as-needed and generally occur when a criti
## Next
- Added an experimental autoloader
- Added the `subpath` argument to `getBasePath()` to make it easier to generate full paths to any file
- Fixed a bug in `<sl-select>` that caused the display label to render incorrectly in Chrome after form validation [#1197](https://github.com/shoelace-style/shoelace/discussions/1197)
- Fixed a bug in `<sl-input>` that prevented users from applying their own value for `autocapitalize`, `autocomplete`, and `autocorrect` when using `type="password` [#1205](https://github.com/shoelace-style/shoelace/issues/1205)

Wyświetl plik

@ -51,6 +51,8 @@ fs.mkdirSync(outdir, { recursive: true });
//
// The whole shebang
'./src/shoelace.ts',
// The auto-loader
'./src/shoelace-autoloader.ts',
// Components
...(await globby('./src/components/**/!(*.(style|test)).ts')),
// Translations
@ -120,6 +122,22 @@ fs.mkdirSync(outdir, { recursive: true });
routes: {
'/dist': './dist'
}
},
//
// Suppress Chrome's document.write() warning
//
// More info: https://github.com/BrowserSync/browser-sync/issues/1600)
//
snippetOptions: {
rule: {
match: /<\/head>/u,
fn: (snippet, match) => {
const {
groups: { src }
} = /src='(?<src>[^']+)'/u.exec(snippet);
return `<script src="${src}" async></script>${match}`;
}
}
}
};

Wyświetl plik

@ -3,7 +3,7 @@ import type { IconLibrary } from './library';
const library: IconLibrary = {
name: 'default',
resolver: name => `${getBasePath()}/assets/icons/${name}.svg`
resolver: name => getBasePath(`assets/icons/${name}.svg`)
};
export default library;

Wyświetl plik

@ -0,0 +1,58 @@
import { getBasePath } from './utilities/base-path';
const observer = new MutationObserver(mutations => {
for (const { addedNodes } of mutations) {
for (const node of addedNodes) {
if (node.nodeType === Node.ELEMENT_NODE) {
discover(node as Element);
}
}
}
});
/**
* Checks a node for undefined elements and attempts to register them.
*/
async function discover(root: Element) {
const rootTagName = root.tagName.toLowerCase();
const rootIsCustomElement = rootTagName.includes('-');
const tags = [...root.querySelectorAll(':not(:defined)')]
.map(el => el.tagName.toLowerCase())
.filter(tag => tag.startsWith('sl-'));
// If the root element is an undefined custom element, add it to the list
if (rootIsCustomElement && !customElements.get(rootTagName)) {
tags.push(root.tagName.toLowerCase());
}
// Make the list unique
const tagsToRegister = [...new Set(tags)];
await Promise.allSettled(tagsToRegister.map(tagName => register(tagName)));
}
/**
* Registers an element by tag name.
*/
function register(tagName: string): Promise<void> {
const tagWithoutPrefix = tagName.replace(/^sl-/i, '');
const path = getBasePath(`components/${tagWithoutPrefix}/${tagWithoutPrefix}.js`);
// If the element is already defined, there's nothing more to do
if (customElements.get(tagName)) {
return Promise.resolve();
}
// Register it
return new Promise((resolve, reject) => {
import(path)
.then(() => resolve())
.catch(() => reject(new Error(`Unable to automatically load<${tagName}> from ${path}`)));
});
}
// Initial discovery
discover(document.body);
// Listen for new undefined elements
observer.observe(document.body, { subtree: true, childList: true });

Wyświetl plik

@ -3,6 +3,7 @@
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
"target": "es2017",
"module": "es2020",
"lib": [
"dom",
"dom.Iterable",