diff --git a/.gitignore b/.gitignore
index 0a2fc3d4..1cf47052 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,8 @@
_site
.cache
.DS_Store
+cdn
dist
docs/assets/images/sprite.svg
node_modules
src/react
-cdn
-web-types.json
\ No newline at end of file
diff --git a/custom-elements-manifest.config.js b/custom-elements-manifest.config.js
index e5912cd0..8d3e7fe5 100644
--- a/custom-elements-manifest.config.js
+++ b/custom-elements-manifest.config.js
@@ -203,6 +203,7 @@ export default {
]
}),
customElementJetBrainsPlugin({
+ outdir: './dist',
excludeCss: true,
referencesTemplate: (_, tag) => {
return {
diff --git a/docs/pages/components/alert.md b/docs/pages/components/alert.md
index a2451e20..5ea30cbb 100644
--- a/docs/pages/components/alert.md
+++ b/docs/pages/components/alert.md
@@ -54,7 +54,7 @@ Set the `variant` attribute to change the alert's variant.
Your settings have been updated
- Settings will take affect on next login.
+ Settings will take effect on next login.
@@ -102,7 +102,7 @@ const App = () => (
Your settings have been updated
- Settings will take affect on next login.
+ Settings will take effect on next login.
@@ -276,7 +276,7 @@ You should always use the `closable` attribute so users can dismiss the notifica
Your settings have been updated
- Settings will take affect on next login.
+ Settings will take effect on next login.
@@ -361,7 +361,7 @@ const App = () => {
Your settings have been updated
- Settings will take affect on next login.
+ Settings will take effect on next login.
diff --git a/docs/pages/components/radio-button.md b/docs/pages/components/radio-button.md
index c7bea66e..fe161c69 100644
--- a/docs/pages/components/radio-button.md
+++ b/docs/pages/components/radio-button.md
@@ -87,26 +87,26 @@ const App = () => (
Use the `size` attribute to change a radio button's size.
```html:preview
-
- Option 1
- Option 2
- Option 3
+
+ Option 1
+ Option 2
+ Option 3
-
- Option 1
- Option 2
- Option 3
+
+ Option 1
+ Option 2
+ Option 3
-
- Option 1
- Option 2
- Option 3
+
+ Option 1
+ Option 2
+ Option 3
```
@@ -115,26 +115,26 @@ import SlRadioButton from '@shoelace-style/shoelace/dist/react/radio-button';
import SlRadioGroup from '@shoelace-style/shoelace/dist/react/radio-group';
const App = () => (
-
- Option 1
- Option 2
- Option 3
+
+ Option 1
+ Option 2
+ Option 3
-
- Option 1
- Option 2
- Option 3
+
+ Option 1
+ Option 2
+ Option 3
-
- Option 1
- Option 2
- Option 3
+
+ Option 1
+ Option 2
+ Option 3
);
```
@@ -144,26 +144,26 @@ const App = () => (
Use the `pill` attribute to give radio buttons rounded edges.
```html:preview
-
- Option 1
- Option 2
- Option 3
+
+ Option 1
+ Option 2
+ Option 3
-
- Option 1
- Option 2
- Option 3
+
+ Option 1
+ Option 2
+ Option 3
-
- Option 1
- Option 2
- Option 3
+
+ Option 1
+ Option 2
+ Option 3
```
@@ -172,26 +172,26 @@ import SlRadioButton from '@shoelace-style/shoelace/dist/react/radio-button';
import SlRadioGroup from '@shoelace-style/shoelace/dist/react/radio-group';
const App = () => (
-
- Option 1
- Option 2
- Option 3
+
+ Option 1
+ Option 2
+ Option 3
-
- Option 1
- Option 2
- Option 3
+
+ Option 1
+ Option 2
+ Option 3
-
- Option 1
- Option 2
- Option 3
+
+ Option 1
+ Option 2
+ Option 3
);
```
diff --git a/docs/pages/frameworks/react.md b/docs/pages/frameworks/react.md
index 86f208ef..b87cb9c7 100644
--- a/docs/pages/frameworks/react.md
+++ b/docs/pages/frameworks/react.md
@@ -32,6 +32,10 @@ If you'd rather not use the CDN for assets, you can create a [build task](https:
Now you can start using components!
+### Preact
+
+Preact users facing type errors using components may benefit from setting "paths" in their tsconfig.json so that react types will instead resolve to preact/compat as described in [Preact's typescript documentation](https://preactjs.com/guide/v10/typescript/#typescript-preactcompat-configuration).
+
## Usage
### Importing Components
diff --git a/docs/pages/getting-started/usage.md b/docs/pages/getting-started/usage.md
index 4032588e..6cf1075d 100644
--- a/docs/pages/getting-started/usage.md
+++ b/docs/pages/getting-started/usage.md
@@ -208,13 +208,13 @@ Shoelace ships with a file called `vscode.html-custom-data.json` that can be use
}
```
-If `settings.json` already exists, simply add the above line to the root of the object. Note that you may need to restart VS Code for the changes to take affect.
+If `settings.json` already exists, simply add the above line to the root of the object. Note that you may need to restart VS Code for the changes to take effect.
-## JetBrains IDEs
+### JetBrains IDEs
If you are using a [JetBrains IDE](https://www.jetbrains.com/) and you are installing Shoelace from NPM, the editor will automatically detect the `web-types.json` file from the package and you should immediately see component information in your editor.
-If you are installing from the CDN, you can [download a local copy](https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace/cdn/web-types.json) and add it to the root of your project.
+If you are installing from the CDN, you can [download a local copy](https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace/dist/web-types.json) and add it to the root of your project.
### Other Editors
diff --git a/docs/pages/resources/changelog.md b/docs/pages/resources/changelog.md
index c6f73cec..b9f57b57 100644
--- a/docs/pages/resources/changelog.md
+++ b/docs/pages/resources/changelog.md
@@ -14,8 +14,13 @@ New versions of Shoelace are released as-needed and generally occur when a criti
## Next
+- Added the `modal` property to `` and `` to support third-party modals [#1571]
+- Fixed a bug in the autoloader causing it to register non-Shoelace elements [#1563]
- Fixed a bug in `` that resulted in improper spacing between the label and the required asterisk [#1540]
+- Fixed a bug in `` that caused icons to not load when the default library used a sprite [#1572]
+- Removed error when a missing popup anchor is provided [#1548]
- Updated `@ctrl/tinycolor` to 4.0.1 [#1542]
+- Updated Bootstrap Icons to 1.11.0
## 2.8.0
diff --git a/package-lock.json b/package-lock.json
index 9379318a..f5355740 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,7 +11,7 @@
"dependencies": {
"@ctrl/tinycolor": "^4.0.1",
"@floating-ui/dom": "^1.2.1",
- "@lit-labs/react": "^2.0.1",
+ "@lit-labs/react": "^2.0.3",
"@shoelace-style/animations": "^1.1.0",
"@shoelace-style/localize": "^3.1.1",
"composed-offset-position": "^0.0.4",
@@ -30,7 +30,7 @@
"@web/test-runner": "^0.15.0",
"@web/test-runner-commands": "^0.6.5",
"@web/test-runner-playwright": "^0.9.0",
- "bootstrap-icons": "^1.10.5",
+ "bootstrap-icons": "^1.11.0",
"browser-sync": "^2.29.3",
"chalk": "^5.2.0",
"change-case": "^4.1.2",
@@ -1474,9 +1474,9 @@
}
},
"node_modules/@lit-labs/react": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@lit-labs/react/-/react-2.0.1.tgz",
- "integrity": "sha512-Nj+XB3HamqaWefN91lpFPJaqjJ78XzGkPWCedB4jyH22GBFEenpE9A/h8B/2dnIGXtNtd9D/RFpUdQ/dBtWFqA==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@lit-labs/react/-/react-2.0.3.tgz",
+ "integrity": "sha512-lSvWbTrbxWqYv/iiOwbAEJfFZrKjO/QjJ4IEXhg43sdD5fNFz4wRXpVsntfVn4DnxpQd+NVRnrsF2USgK0XCTw==",
"peerDependencies": {
"@types/react": "17 || 18"
}
@@ -3988,9 +3988,9 @@
}
},
"node_modules/bootstrap-icons": {
- "version": "1.10.5",
- "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.10.5.tgz",
- "integrity": "sha512-oSX26F37V7QV7NCE53PPEL45d7EGXmBgHG3pDpZvcRaKVzWMqIRL9wcqJUyEha1esFtM3NJzvmxFXDxjJYD0jQ==",
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.0.tgz",
+ "integrity": "sha512-bLTbtACfUqwZf6f/xUYUb7bTRZC68QaQwwy9h1b96NPKfnwqzSatHqDypW6R2CBW7zUE7lP+O93GdZuPY3RIHA==",
"dev": true,
"funding": [
{
@@ -18290,9 +18290,9 @@
}
},
"@lit-labs/react": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@lit-labs/react/-/react-2.0.1.tgz",
- "integrity": "sha512-Nj+XB3HamqaWefN91lpFPJaqjJ78XzGkPWCedB4jyH22GBFEenpE9A/h8B/2dnIGXtNtd9D/RFpUdQ/dBtWFqA==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@lit-labs/react/-/react-2.0.3.tgz",
+ "integrity": "sha512-lSvWbTrbxWqYv/iiOwbAEJfFZrKjO/QjJ4IEXhg43sdD5fNFz4wRXpVsntfVn4DnxpQd+NVRnrsF2USgK0XCTw==",
"requires": {}
},
"@lit-labs/ssr-dom-shim": {
@@ -20213,9 +20213,9 @@
}
},
"bootstrap-icons": {
- "version": "1.10.5",
- "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.10.5.tgz",
- "integrity": "sha512-oSX26F37V7QV7NCE53PPEL45d7EGXmBgHG3pDpZvcRaKVzWMqIRL9wcqJUyEha1esFtM3NJzvmxFXDxjJYD0jQ==",
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.0.tgz",
+ "integrity": "sha512-bLTbtACfUqwZf6f/xUYUb7bTRZC68QaQwwy9h1b96NPKfnwqzSatHqDypW6R2CBW7zUE7lP+O93GdZuPY3RIHA==",
"dev": true
},
"boxen": {
diff --git a/package.json b/package.json
index 5cca9356..a0de7626 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"author": "Cory LaViska",
"license": "MIT",
"customElements": "dist/custom-elements.json",
- "web-types": "./web-types.json",
+ "web-types": "./dist/web-types.json",
"type": "module",
"types": "dist/shoelace.d.ts",
"jsdelivr": "./cdn/shoelace-autoloader.js",
@@ -62,7 +62,7 @@
"dependencies": {
"@ctrl/tinycolor": "^4.0.1",
"@floating-ui/dom": "^1.2.1",
- "@lit-labs/react": "^2.0.1",
+ "@lit-labs/react": "^2.0.3",
"@shoelace-style/animations": "^1.1.0",
"@shoelace-style/localize": "^3.1.1",
"composed-offset-position": "^0.0.4",
@@ -81,7 +81,7 @@
"@web/test-runner": "^0.15.0",
"@web/test-runner-commands": "^0.6.5",
"@web/test-runner-playwright": "^0.9.0",
- "bootstrap-icons": "^1.10.5",
+ "bootstrap-icons": "^1.11.0",
"browser-sync": "^2.29.3",
"chalk": "^5.2.0",
"change-case": "^4.1.2",
diff --git a/scripts/build.js b/scripts/build.js
index e46f4ef9..ef6c2846 100644
--- a/scripts/build.js
+++ b/scripts/build.js
@@ -34,6 +34,9 @@ const shoelaceVersion = JSON.stringify(packageData.version.toString());
async function buildTheDocs(watch = false) {
return new Promise(async (resolve, reject) => {
const afterSignal = '[eleventy.after]';
+
+ // Totally non-scientific way to handle errors. Perhaps its just better to resolve on stderr? :shrug:
+ const errorSignal = 'Original error stack trace:';
const args = ['@11ty/eleventy', '--quiet'];
const output = [];
@@ -65,6 +68,13 @@ async function buildTheDocs(watch = false) {
resolve({ child, output });
}
});
+
+ child.stderr.on('data', data => {
+ if (data.includes(errorSignal)) {
+ // This closes the dev server, not sure if thats what we want?
+ reject(output);
+ }
+ });
} else {
child.on('close', () => {
resolve({ child, output });
@@ -205,9 +215,8 @@ await nextTask('Running the TypeScript compiler', () => {
});
// Copy the above steps to the CDN directory directly so we don't need to twice the work for nothing.
-await nextTask(`Copying Web Types, Themes, Icons, and TS Types to "${cdndir}"`, async () => {
+await nextTask(`Themes, Icons, and TS Types to "${cdndir}"`, async () => {
await deleteAsync(cdndir);
- await copy('./web-types.json', `${outdir}/web-types.json`);
await copy(outdir, cdndir);
});
diff --git a/src/components/details/details.component.ts b/src/components/details/details.component.ts
index b7eab446..d8b83a43 100644
--- a/src/components/details/details.component.ts
+++ b/src/components/details/details.component.ts
@@ -87,6 +87,7 @@ export default class SlDetails extends ShoelaceElement {
}
disconnectedCallback() {
+ super.disconnectedCallback();
this.detailsObserver.disconnect();
}
diff --git a/src/components/dialog/dialog.component.ts b/src/components/dialog/dialog.component.ts
index 7e708db1..30afa3d5 100644
--- a/src/components/dialog/dialog.component.ts
+++ b/src/components/dialog/dialog.component.ts
@@ -60,6 +60,10 @@ import type { CSSResultGroup } from 'lit';
* @animation dialog.denyClose - The animation to use when a request to close the dialog is denied.
* @animation dialog.overlay.show - The animation to use when showing the dialog's overlay.
* @animation dialog.overlay.hide - The animation to use when hiding the dialog's overlay.
+ *
+ * @property modal - Exposes the internal modal utility that controls focus trapping. To temporarily disable focus
+ * trapping and allow third-party modals spawned from an active Shoelace modal, call `modal.activateExternal()` when
+ * the third-party modal opens. Upon closing, call `modal.deactivateExternal()` to restore Shoelace's focus trapping.
*/
export default class SlDialog extends ShoelaceElement {
static styles: CSSResultGroup = styles;
@@ -69,8 +73,8 @@ export default class SlDialog extends ShoelaceElement {
private readonly hasSlotController = new HasSlotController(this, 'footer');
private readonly localize = new LocalizeController(this);
- private modal = new Modal(this);
private originalTrigger: HTMLElement | null;
+ public modal = new Modal(this);
@query('.dialog') dialog: HTMLElement;
@query('.dialog__panel') panel: HTMLElement;
diff --git a/src/components/drawer/drawer.component.ts b/src/components/drawer/drawer.component.ts
index 6ce9e885..d3a84171 100644
--- a/src/components/drawer/drawer.component.ts
+++ b/src/components/drawer/drawer.component.ts
@@ -68,6 +68,10 @@ import type { CSSResultGroup } from 'lit';
* @animation drawer.denyClose - The animation to use when a request to close the drawer is denied.
* @animation drawer.overlay.show - The animation to use when showing the drawer's overlay.
* @animation drawer.overlay.hide - The animation to use when hiding the drawer's overlay.
+ *
+ * @property modal - Exposes the internal modal utility that controls focus trapping. To temporarily disable focus
+ * trapping and allow third-party modals spawned from an active Shoelace modal, call `modal.activateExternal()` when
+ * the third-party modal opens. Upon closing, call `modal.deactivateExternal()` to restore Shoelace's focus trapping.
*/
export default class SlDrawer extends ShoelaceElement {
static styles: CSSResultGroup = styles;
@@ -75,8 +79,8 @@ export default class SlDrawer extends ShoelaceElement {
private readonly hasSlotController = new HasSlotController(this, 'footer');
private readonly localize = new LocalizeController(this);
- private modal = new Modal(this);
private originalTrigger: HTMLElement | null;
+ public modal = new Modal(this);
@query('.drawer') drawer: HTMLElement;
@query('.drawer__panel') panel: HTMLElement;
diff --git a/src/components/icon/icon.component.ts b/src/components/icon/icon.component.ts
index 4f379de9..542ede6e 100644
--- a/src/components/icon/icon.component.ts
+++ b/src/components/icon/icon.component.ts
@@ -15,6 +15,11 @@ type SVGResult = HTMLTemplateResult | SVGSVGElement | typeof RETRYABLE_ERROR | t
let parser: DOMParser;
const iconCache = new Map>();
+interface IconSource {
+ url?: string;
+ fromLibrary: boolean;
+}
+
/**
* @summary Icons are symbols that can be used to represent various options within an application.
* @documentation https://shoelace.style/components/icon
@@ -104,12 +109,19 @@ export default class SlIcon extends ShoelaceElement {
unwatchIcon(this);
}
- private getUrl() {
+ private getIconSource(): IconSource {
const library = getIconLibrary(this.library);
if (this.name && library) {
- return library.resolver(this.name);
+ return {
+ url: library.resolver(this.name),
+ fromLibrary: true
+ };
}
- return this.src;
+
+ return {
+ url: this.src,
+ fromLibrary: false
+ };
}
@watch('label')
@@ -129,8 +141,8 @@ export default class SlIcon extends ShoelaceElement {
@watch(['name', 'src', 'library'])
async setIcon() {
- const library = getIconLibrary(this.library);
- const url = this.getUrl();
+ const { url, fromLibrary } = this.getIconSource();
+ const library = fromLibrary ? getIconLibrary(this.library) : undefined;
if (!url) {
this.svg = null;
@@ -154,7 +166,7 @@ export default class SlIcon extends ShoelaceElement {
iconCache.delete(url);
}
- if (url !== this.getUrl()) {
+ if (url !== this.getIconSource().url) {
// If the url has changed while fetching the icon, ignore this request
return;
}
diff --git a/src/components/mutation-observer/mutation-observer.component.ts b/src/components/mutation-observer/mutation-observer.component.ts
index 61b05ce4..85ed39e7 100644
--- a/src/components/mutation-observer/mutation-observer.component.ts
+++ b/src/components/mutation-observer/mutation-observer.component.ts
@@ -52,6 +52,7 @@ export default class SlMutationObserver extends ShoelaceElement {
}
disconnectedCallback() {
+ super.disconnectedCallback();
this.stopObserver();
}
diff --git a/src/components/popup/popup.component.ts b/src/components/popup/popup.component.ts
index 3ab4c0d1..93bda74c 100644
--- a/src/components/popup/popup.component.ts
+++ b/src/components/popup/popup.component.ts
@@ -198,6 +198,7 @@ export default class SlPopup extends ShoelaceElement {
}
disconnectedCallback() {
+ super.disconnectedCallback();
this.stop();
}
@@ -246,13 +247,10 @@ export default class SlPopup extends ShoelaceElement {
this.anchorEl = this.anchorEl.assignedElements({ flatten: true })[0] as HTMLElement;
}
- if (!this.anchorEl) {
- throw new Error(
- 'Invalid anchor element: no anchor could be found using the anchor slot or the anchor attribute.'
- );
+ // If the anchor is valid, start it up
+ if (this.anchorEl) {
+ this.start();
}
-
- this.start();
}
private start() {
diff --git a/src/components/tab-group/tab-group.component.ts b/src/components/tab-group/tab-group.component.ts
index f1753807..27ecf18a 100644
--- a/src/components/tab-group/tab-group.component.ts
+++ b/src/components/tab-group/tab-group.component.ts
@@ -117,6 +117,7 @@ export default class SlTabGroup extends ShoelaceElement {
}
disconnectedCallback() {
+ super.disconnectedCallback();
this.mutationObserver.disconnect();
this.resizeObserver.unobserve(this.nav);
}
diff --git a/src/internal/modal.ts b/src/internal/modal.ts
index 680a0e97..40128393 100644
--- a/src/internal/modal.ts
+++ b/src/internal/modal.ts
@@ -5,6 +5,7 @@ let activeModals: HTMLElement[] = [];
export default class Modal {
element: HTMLElement;
+ isExternalActivated: boolean;
tabDirection: 'forward' | 'backward' = 'forward';
currentFocus: HTMLElement | null;
@@ -12,6 +13,7 @@ export default class Modal {
this.element = element;
}
+ /** Activates focus trapping. */
activate() {
activeModals.push(this.element);
document.addEventListener('focusin', this.handleFocusIn);
@@ -19,6 +21,7 @@ export default class Modal {
document.addEventListener('keyup', this.handleKeyUp);
}
+ /** Deactivates focus trapping. */
deactivate() {
activeModals = activeModals.filter(modal => modal !== this.element);
this.currentFocus = null;
@@ -27,13 +30,24 @@ export default class Modal {
document.removeEventListener('keyup', this.handleKeyUp);
}
+ /** Determines if this modal element is currently active or not. */
isActive() {
// The "active" modal is always the most recent one shown
return activeModals[activeModals.length - 1] === this.element;
}
- checkFocus() {
- if (this.isActive()) {
+ /** Activates external modal behavior and temporarily disables focus trapping. */
+ activateExternal() {
+ this.isExternalActivated = true;
+ }
+
+ /** Deactivates external modal behavior and re-enables focus trapping. */
+ deactivateExternal() {
+ this.isExternalActivated = false;
+ }
+
+ private checkFocus() {
+ if (this.isActive() && !this.isExternalActivated) {
const tabbableElements = getTabbableElements(this.element);
if (!this.element.matches(':focus-within')) {
const start = tabbableElements[0];
@@ -56,11 +70,9 @@ export default class Modal {
return getTabbableElements(this.element).findIndex(el => el === this.currentFocus);
}
- /**
- * Checks if the `startElement` is already focused. This is important if the modal already
- * has an existing focus prior to the first tab key.
- */
- startElementAlreadyFocused(startElement: HTMLElement) {
+ // Checks if the `startElement` is already focused. This is important if the modal already has an existing focus prior
+ // to the first tab key.
+ private startElementAlreadyFocused(startElement: HTMLElement) {
for (const activeElement of activeElements()) {
if (startElement === activeElement) {
return true;
@@ -70,8 +82,8 @@ export default class Modal {
return false;
}
- handleKeyDown = (event: KeyboardEvent) => {
- if (event.key !== 'Tab') return;
+ private handleKeyDown = (event: KeyboardEvent) => {
+ if (event.key !== 'Tab' || this.isExternalActivated) return;
if (event.shiftKey) {
this.tabDirection = 'backward';
diff --git a/src/shoelace-autoloader.ts b/src/shoelace-autoloader.ts
index a0d66c00..4b42c452 100644
--- a/src/shoelace-autoloader.ts
+++ b/src/shoelace-autoloader.ts
@@ -15,13 +15,13 @@ const observer = new MutationObserver(mutations => {
*/
export async function discover(root: Element | ShadowRoot) {
const rootTagName = root instanceof Element ? root.tagName.toLowerCase() : '';
- const rootIsCustomElement = rootTagName?.includes('-');
+ const rootIsShoelaceElement = rootTagName?.startsWith('sl-');
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)) {
+ // If the root element is an undefined Shoelace component, add it to the list
+ if (rootIsShoelaceElement && !customElements.get(rootTagName)) {
tags.push(rootTagName);
}
@@ -35,14 +35,14 @@ export async function discover(root: Element | ShadowRoot) {
* Registers an element by tag name.
*/
function register(tagName: string): Promise {
- 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();
}
+ const tagWithoutPrefix = tagName.replace(/^sl-/i, '');
+ const path = getBasePath(`components/${tagWithoutPrefix}/${tagWithoutPrefix}.js`);
+
// Register it
return new Promise((resolve, reject) => {
import(path).then(() => resolve()).catch(() => reject(new Error(`Unable to autoload <${tagName}> from ${path}`)));
diff --git a/src/translations/de.ts b/src/translations/de.ts
index 1894e600..21b1e069 100644
--- a/src/translations/de.ts
+++ b/src/translations/de.ts
@@ -13,7 +13,7 @@ const translation: Translation = {
copy: 'Kopieren',
currentValue: 'Aktueller Wert',
error: 'Fehler',
- goToSlide: (slide, count) => `Gehen Sie zu Folie ${slide} von ${count}`,
+ goToSlide: (slide, count) => `Zu Folie ${slide} von ${count} gehen`,
hidePassword: 'Passwort verbergen',
loading: 'Wird geladen',
nextSlide: 'Nächste Folie',
@@ -28,7 +28,7 @@ const translation: Translation = {
resize: 'Größe ändern',
scrollToEnd: 'Zum Ende scrollen',
scrollToStart: 'Zum Anfang scrollen',
- selectAColorFromTheScreen: 'Wähle eine Farbe vom Bildschirm',
+ selectAColorFromTheScreen: 'Farbe vom Bildschirm auswählen',
showPassword: 'Passwort anzeigen',
slideNum: slide => `Folie ${slide}`,
toggleColorFormat: 'Farbformat umschalten'