(view);\n if (typeof customView === 'object') {\n customView.providers = this.providers.map((provider) => provider.value);\n customView.returnPath = umbAuthContext.returnPath;\n }\n return renderCustomView(customView);\n } catch (e) {\n const error = e instanceof Error ? e.message : 'Unknown error';\n console.group('[MFA login] Failed to load custom view');\n console.log('Element reference', this);\n console.log('Custom view', view);\n console.error('Failed to load custom view:', e);\n console.groupEnd();\n return html`${error}`;\n }\n }\n\n protected render() {\n return this.loading\n ? html`\n `\n : umbAuthContext.twoFactorView\n ? until(this.renderCustomView(), html`\n `)\n : this.renderDefaultView();\n }\n\n static styles = [\n css`\n #header {\n text-align: center;\n }\n\n #header h1 {\n font-weight: 400;\n font-size: var(--header-secondary-font-size);\n color: var(--uui-color-interactive);\n line-height: 1.2;\n }\n\n form {\n display: flex;\n flex-direction: column;\n gap: var(--uui-size-layout-2);\n }\n\n #provider {\n width: 100%;\n }\n\n uui-form-layout-item {\n margin: 0;\n }\n\n uui-input,\n uui-input-password {\n width: 100%;\n height: var(--input-height);\n border-radius: var(--uui-border-radius);\n }\n\n uui-input {\n width: 100%;\n }\n\n uui-button {\n width: 100%;\n --uui-button-padding-top-factor: 1.5;\n --uui-button-padding-bottom-factor: 1.5;\n }\n\n .text-danger {\n color: var(--uui-color-danger-standalone);\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'umb-mfa-page': UmbMfaPageElement;\n }\n}\n","import type {UUIButtonState} from '@umbraco-ui/uui';\nimport {css, CSSResultGroup, html, LitElement, nothing} from 'lit';\nimport {customElement, property, queryAssignedElements, state} from 'lit/decorators.js';\nimport {when} from 'lit/directives/when.js';\nimport {until} from 'lit/directives/until.js';\n\nimport {umbAuthContext} from '../../context/auth.context.js';\nimport {umbLocalizationContext} from '../../external/localization/localization-context.js';\n\n@customElement('umb-login-page')\nexport default class UmbLoginPageElement extends LitElement {\n @property({type: Boolean, attribute: 'username-is-email'})\n usernameIsEmail = false;\n\n @queryAssignedElements({flatten: true})\n protected slottedElements?: HTMLFormElement[];\n\n @property({type: Boolean, attribute: 'allow-password-reset'})\n allowPasswordReset = false;\n\n @state()\n private _loginState: UUIButtonState = undefined;\n\n @state()\n private _loginError = '';\n\n @state()\n private get disableLocalLogin() {\n return umbAuthContext.disableLocalLogin;\n }\n\n #formElement?: HTMLFormElement;\n\n async #onSlotChanged() {\n this.#formElement = this.slottedElements?.find((el) => el.id === 'umb-login-form');\n\n if (!this.#formElement) return;\n\n // We need to listen for the enter key to submit the form, because the uui-button does not support the native input fields submit event\n this.#formElement.addEventListener('keypress', (e) => {\n if (e.key === 'Enter') {\n this.#onSubmitClick();\n }\n });\n\n this.#formElement.onsubmit = this.#handleSubmit;\n }\n\n #handleSubmit = async (e: SubmitEvent) => {\n e.preventDefault();\n\n const form = e.target as HTMLFormElement;\n if (!form) return;\n\n if (!form.checkValidity()) return;\n\n const formData = new FormData(form);\n\n const username = formData.get('username') as string;\n const password = formData.get('password') as string;\n const persist = formData.has('persist');\n\n if (!username || !password) {\n this._loginError = await umbLocalizationContext.localize('auth_userFailedLogin');\n this._loginState = 'failed';\n return;\n }\n\n this._loginState = 'waiting';\n\n const response = await umbAuthContext.login({\n username,\n password,\n persist,\n });\n\n this._loginError = response.error || '';\n this._loginState = response.error ? 'failed' : 'success';\n\n // Check for 402 status code indicating that MFA is required\n if (response.status === 402) {\n umbAuthContext.isMfaEnabled = true;\n if (response.twoFactorView) {\n umbAuthContext.twoFactorView = response.twoFactorView;\n }\n\n this.dispatchEvent(new CustomEvent('umb-login-flow', {composed: true, detail: {flow: 'mfa'}}));\n return;\n }\n\n if (response.error) {\n this.dispatchEvent(new CustomEvent('umb-login-failed', {bubbles: true, composed: true, detail: response}));\n return;\n }\n\n const returnPath = umbAuthContext.returnPath;\n\n if (returnPath) {\n location.href = returnPath;\n }\n\n this.dispatchEvent(new CustomEvent('umb-login-success', {bubbles: true, composed: true, detail: response.data}));\n };\n\n get #greetingLocalizationKey() {\n return [\n 'login_greeting0',\n 'login_greeting1',\n 'login_greeting2',\n 'login_greeting3',\n 'login_greeting4',\n 'login_greeting5',\n 'login_greeting6',\n ][new Date().getDay()];\n }\n\n #onSubmitClick = () => {\n this.#formElement?.requestSubmit();\n };\n\n render() {\n return html`\n \n ${this.disableLocalLogin\n ? nothing\n : html`\n \n \n ${when(\n umbAuthContext.supportsPersistLogin,\n () => html`\n \n \n Remember me\n \n `\n )}\n ${when(\n this.allowPasswordReset,\n () =>\n html`\n `\n )}\n
\n \n\n ${this.#renderErrorMessage()}\n `}\n \n \n \n `;\n }\n\n #renderErrorMessage() {\n if (!this._loginError || this._loginState !== 'failed') return nothing;\n\n return html`${this._loginError}`;\n }\n\n #handleForgottenPassword() {\n this.dispatchEvent(new CustomEvent('umb-login-flow', {composed: true, detail: {flow: 'reset'}}));\n }\n\n static styles: CSSResultGroup = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n }\n\n #header {\n text-align: center;\n display: flex;\n flex-direction: column;\n gap: var(--uui-size-space-5);\n }\n\n #header span {\n color: var(--uui-color-text-alt); /* TODO Change to uui color when uui gets a muted text variable */\n font-size: 14px;\n }\n\n #greeting {\n color: var(--uui-color-interactive);\n text-align: center;\n font-weight: 400;\n font-size: var(--header-font-size);\n margin: 0 0 var(--uui-size-layout-1);\n line-height: 1.2;\n }\n\n #umb-login-button {\n margin-top: var(--uui-size-space-4);\n width: 100%;\n }\n\n #forgot-password {\n cursor: pointer;\n background: none;\n border: 0;\n height: 1rem;\n color: var(--uui-color-text-alt); /* TODO Change to uui color when uui gets a muted text variable */\n gap: var(--uui-size-space-1);\n align-self: center;\n text-decoration: none;\n display: inline-flex;\n line-height: 1;\n font-size: 14px;\n font-family: var(--uui-font-family);\n margin-left: auto;\n margin-bottom: var(--uui-size-space-3);\n }\n\n #forgot-password:hover {\n color: var(--uui-color-interactive-emphasis);\n }\n\n .text-error {\n margin-top: var(--uui-size-space-4);\n }\n\n .text-danger {\n color: var(--uui-color-danger-standalone);\n }\n\n #secondary-actions {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'umb-login-page': UmbLoginPageElement;\n }\n}\n","import type { UUIButtonState } from '@umbraco-ui/uui';\nimport { LitElement, html } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { until } from 'lit/directives/until.js';\n\nimport { umbAuthContext } from '../../context/auth.context.js';\nimport { umbLocalizationContext } from '../../external/localization/localization-context.js';\n\n@customElement('umb-invite-page')\nexport default class UmbInvitePageElement extends LitElement {\n @state()\n state: UUIButtonState = undefined;\n\n @state()\n error = '';\n\n @state()\n invitedUser?: any;\n\n protected async firstUpdated(_changedProperties: any) {\n super.firstUpdated(_changedProperties);\n\n const response = await umbAuthContext.getInvitedUser();\n\n if (!response.user?.id) {\n // The login page should already have redirected the user to an error page. They should never get here.\n this.error = 'No invited user found';\n return;\n }\n\n this.invitedUser = response.user;\n }\n\n async #onSubmit(event: CustomEvent) {\n event.preventDefault();\n const password = event.detail.password;\n\n if (!password) return;\n\n this.state = 'waiting';\n const response = await umbAuthContext.newInvitedUserPassword(password);\n\n if (response.error) {\n this.error = response.error;\n this.state = 'failed';\n return;\n }\n\n this.state = 'success';\n window.location.href = umbAuthContext.returnPath;\n }\n\n render() {\n return this.invitedUser\n ? html`\n `\n : this.error\n ? html`\n `\n : html`\n \n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'umb-invite-page': UmbInvitePageElement;\n }\n}\n","import { css, CSSResultGroup, html, LitElement, nothing } from 'lit';\nimport { customElement, property, queryAssignedElements } from 'lit/decorators.js';\nimport { until } from 'lit/directives/until.js';\nimport { umbLocalizationContext } from '../../external/localization/localization-context.js';\n\n@customElement('umb-external-login-providers-layout')\nexport class UmbExternalLoginProvidersLayoutElement extends LitElement {\n @property({ type: Boolean, attribute: 'divider' })\n showDivider = true;\n\n @queryAssignedElements({ flatten: true })\n protected slottedElements?: HTMLElement[];\n\n firstUpdated() {\n !!this.slottedElements?.length ? this.toggleAttribute('empty', false) : this.toggleAttribute('empty', true);\n }\n\n render() {\n return html`\n ${this.showDivider\n ? html`\n \n ${until(umbLocalizationContext.localize('general_or', undefined, 'or').then(str => str.toLocaleLowerCase()))}\n
\n `\n : nothing}\n \n \n
\n `;\n }\n\n static styles: CSSResultGroup = [\n css`\n :host {\n margin-top: 16px;\n display: flex;\n flex-direction: column;\n }\n\n :host([empty]) {\n display: none;\n }\n\n slot {\n display: flex;\n flex-direction: column;\n gap: var(--uui-size-space-4);\n }\n\n #divider {\n width: calc(100% - 18px);\n margin: 0 auto;\n margin-bottom: 16px;\n text-align: center;\n z-index: 0;\n overflow: hidden;\n }\n\n #divider span {\n padding-inline: 10px;\n position: relative;\n color: var(--uui-color-border-emphasis);\n }\n\n #divider span::before,\n #divider span::after {\n content: '';\n display: block;\n width: 500px; /* Arbitrary value, just be bigger than 50% of the max width of the container */\n height: 1px;\n background-color: var(--uui-color-border);\n position: absolute;\n top: calc(50% + 1px);\n }\n\n #divider span::before {\n right: 100%;\n }\n\n #divider span::after {\n left: 100%;\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'umb-external-login-providers-layout': UmbExternalLoginProvidersLayoutElement;\n }\n}\n","import type { UUIInterfaceColor, UUIInterfaceLook } from '@umbraco-ui/uui';\nimport { css, CSSResultGroup, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { until } from 'lit/directives/until.js';\n\nimport { loadCustomView, renderCustomView } from '../utils/load-custom-view.function.js';\nimport { umbLocalizationContext } from '../external/localization/localization-context.js';\n\ntype UserViewState = 'loggingIn' | 'loggedIn' | 'loggedOut' | 'timedOut';\n\ntype ExternalLoginCustomViewElement = HTMLElement & {\n displayName?: string;\n providerName?: string;\n externalLoginUrl?: string;\n userViewState?: UserViewState;\n};\n\n/**\n * This elements represents a single external login provider and should be slotted into the element.\n *\n * @element umb-external-login-provider\n */\n@customElement('umb-external-login-provider')\nexport class UmbExternalLoginProviderElement extends LitElement {\n /**\n * Gets or sets the path to the module that should be loaded as the custom view.\n * The module should export a default class that extends HTMLElement.\n *\n * Setting this property will cause the default view to be hidden and the custom view to be loaded.\n * The icon, button look and button color will be ignored.\n *\n * @example App_Plugins/MyPackage/MyCustomLoginView.js\n * @attr custom-view\n */\n @property({attribute: 'custom-view'})\n customView?: string;\n\n /**\n * Gets or sets the display name of the provider.\n *\n * @attr display-name\n * @example Google\n */\n @property({attribute: 'display-name'})\n displayName = '';\n\n /**\n * Gets or sets the name of the provider (otherwise known as authentication type).\n *\n * @attr provider-name\n * @example Umbraco.Google\n */\n @property({attribute: 'provider-name'})\n providerName = '';\n\n /**\n * Gets or sets the view state of the user. This indicates in which state the user is in the login process,\n * which can be used to determine where the external-login-provider is being shown.\n *\n * @attr user-view-state\n * @example loggingIn\n * @default loggingIn\n */\n @property({attribute: 'user-view-state'})\n userViewState: UserViewState = 'loggingIn';\n\n /**\n * Gets or sets the url to the external login provider.\n *\n * @attr external-login-url\n * @example /umbraco/ExternalLogin\n */\n @property({attribute: 'external-login-url'})\n set externalLoginUrl(value: string) {\n const tempUrl = new URL(value, window.location.origin);\n const searchParams = new URLSearchParams(window.location.search);\n tempUrl.searchParams.append('redirectUrl', decodeURIComponent(searchParams.get('returnPath') ?? ''));\n this.#externalLoginUrl = tempUrl.pathname + tempUrl.search;\n }\n\n get externalLoginUrl() {\n return this.#externalLoginUrl;\n }\n\n /**\n * Gets or sets the icon to display next to the provider name.\n * This should be the name of an icon in the Umbraco Backoffice icon set.\n *\n * @attr icon\n * @example icon-google-fill\n * @default icon-lock\n */\n @property({attribute: 'icon'})\n icon = 'icon-lock';\n\n /**\n * Gets or sets the look of the underlying uui-button.\n *\n * @attr button-look\n * @example outline\n * @default outline\n * @see https://uui.umbraco.com/?path=/story/uui-button--looks-and-colors\n */\n @property({attribute: 'button-look'})\n buttonLook: UUIInterfaceLook = 'outline';\n\n /**\n * Gets or sets the color of the underlying uui-button.\n *\n * @attr button-color\n * @example danger\n * @default default\n * @see https://uui.umbraco.com/?path=/story/uui-button--looks-and-colors\n */\n @property({attribute: 'button-color'})\n buttonColor: UUIInterfaceColor = 'default';\n\n #externalLoginUrl = '';\n\n constructor() {\n super();\n\n const searchParams = new URLSearchParams(window.location.search);\n const isLogout = searchParams.get('logout') === 'true';\n\n if (isLogout) {\n this.userViewState = 'loggedOut';\n }\n }\n\n protected render() {\n return this.customView\n ? until(this.renderCustomView(), html`\n `)\n : this.renderDefaultView();\n }\n\n protected renderDefaultView() {\n return html`\n \n `;\n }\n\n protected async renderCustomView() {\n try {\n if (!this.customView) return;\n\n const customView = await loadCustomView(this.customView);\n\n if (typeof customView === 'object') {\n customView.displayName = this.displayName;\n customView.providerName = this.providerName;\n customView.externalLoginUrl = this.externalLoginUrl;\n customView.userViewState = this.userViewState;\n }\n\n return renderCustomView(customView);\n } catch (error: unknown) {\n console.group('[External login] Failed to load custom view');\n console.log('Provider name', this.providerName);\n console.log('Element reference', this);\n console.log('Custom view', this.customView);\n console.error('Failed to load custom view:', error);\n console.groupEnd();\n }\n }\n\n static styles: CSSResultGroup = [\n css`\n #defaultView uui-button {\n width: 100%;\n --uui-button-font-weight: 400;\n }\n\n #defaultView uui-button div {\n /* TODO: Remove this when uui-button has setting for aligning content */\n position: absolute;\n top: 50%;\n left: 0;\n margin: auto;\n transform: translateY(-50%);\n text-align: left;\n padding-left: 15px;\n }\n\n #defaultView uui-icon {\n\t\t\t\topacity: 0.85;\n padding-right: 2px;\n }\n\n #defaultView button {\n font-size: var(--uui-button-font-size);\n border: 1px solid var(--uui-color-border);\n border-radius: var(--uui-button-border-radius);\n width: 100%;\n padding: 9px;\n text-align: left;\n background-color: var(--uui-color-surface);\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: var(--uui-size-space-2);\n box-sizing: border-box;\n\n line-height: 1.1; /* makes the text vertically centered */\n color: var(--uui-color-interactive);\n }\n\n #defaultView button:hover {\n color: var(--uui-color-interactive-emphasis);\n border-color: var(--uui-color-border-standalone);\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'umb-external-login-provider': UmbExternalLoginProviderElement;\n }\n}\n","import type {UUIButtonState, UUIInputPasswordElement} from '@umbraco-ui/uui';\nimport {CSSResultGroup, LitElement, css, html, nothing} from 'lit';\nimport {customElement, property, query, state} from 'lit/decorators.js';\nimport {until} from 'lit/directives/until.js';\n\nimport {umbAuthContext} from '../../context/auth.context.js';\nimport {umbLocalizationContext} from '../../external/localization/localization-context.js';\n\n@customElement('umb-new-password-layout')\nexport default class UmbNewPasswordLayoutElement extends LitElement {\n @query('#password')\n passwordElement!: UUIInputPasswordElement;\n\n @query('#confirmPassword')\n confirmPasswordElement!: UUIInputPasswordElement;\n\n @property()\n state: UUIButtonState = undefined;\n\n @property()\n error: string = '';\n\n @property()\n userId: any;\n\n @property()\n userName?: string;\n\n @state()\n passwordConfig?: {\n allowManuallyChangingPassword: boolean;\n minNonAlphaNumericChars: number;\n minPasswordLength: number;\n };\n\n protected async firstUpdated(_changedProperties: any) {\n super.firstUpdated(_changedProperties);\n\n if (this.userId) {\n const response = await umbAuthContext.getPasswordConfig(this.userId);\n this.passwordConfig = response.data;\n }\n }\n\n async #onSubmit(event: Event) {\n event.preventDefault();\n if (!this.passwordConfig) return;\n const form = event.target as HTMLFormElement;\n\n this.passwordElement.setCustomValidity('');\n this.confirmPasswordElement.setCustomValidity('');\n\n if (!form) return;\n if (!form.checkValidity()) return;\n\n const formData = new FormData(form);\n const password = formData.get('password') as string;\n const passwordConfirm = formData.get('confirmPassword') as string;\n\n let passwordIsInvalid = false;\n\n if (this.passwordConfig.minPasswordLength > 0 && password.length < this.passwordConfig.minPasswordLength) {\n passwordIsInvalid = true;\n }\n\n if (this.passwordConfig.minNonAlphaNumericChars > 0) {\n const nonAlphaNumericChars = password.replace(/[a-zA-Z0-9]/g, '').length; //TODO: How should we check for non-alphanumeric chars?\n if (nonAlphaNumericChars < this.passwordConfig?.minNonAlphaNumericChars) {\n passwordIsInvalid = true;\n }\n }\n\n if (passwordIsInvalid) {\n const passwordValidityText = await umbLocalizationContext.localize(\n 'errorHandling_errorInPasswordFormat',\n [this.passwordConfig.minPasswordLength, this.passwordConfig.minNonAlphaNumericChars],\n \"The password doesn't meet the minimum requirements!\"\n );\n this.passwordElement.setCustomValidity(passwordValidityText);\n return;\n }\n\n if (password !== passwordConfirm) {\n const passwordValidityText = await umbLocalizationContext.localize(\n 'user_passwordMismatch',\n undefined,\n \"The confirmed password doesn't match the new password!\"\n );\n this.confirmPasswordElement.setCustomValidity(passwordValidityText);\n return;\n }\n\n this.dispatchEvent(new CustomEvent('submit', {detail: {password}}));\n }\n\n renderHeader() {\n if (this.userName) {\n return html`\n Hi, ${this.userName}
\n \n \n Welcome to Umbraco! Just need to get your password setup and then you're good to go\n \n \n `;\n } else {\n return html`\n \n New password\n
\n \n Please provide a new password.\n \n `;\n }\n }\n\n render() {\n return html`\n \n \n \n\n \n `;\n }\n\n #renderErrorMessage() {\n if (!this.error || this.state !== 'failed') return nothing;\n\n return html`${this.error}`;\n }\n\n static styles: CSSResultGroup = [\n css`\n #header {\n text-align: center;\n display: flex;\n flex-direction: column;\n gap: var(--uui-size-space-5);\n }\n\n #header span {\n color: var(--uui-color-text-alt); /* TODO Change to uui color when uui gets a muted text variable */\n font-size: 14px;\n }\n\n #header h1 {\n margin: 0;\n font-weight: 400;\n font-size: var(--header-secondary-font-size);\n color: var(--uui-color-interactive);\n line-height: 1.2;\n }\n\n form {\n display: flex;\n flex-direction: column;\n gap: var(--uui-size-space-5);\n }\n\n uui-form-layout-item {\n margin: 0;\n }\n\n uui-input-password {\n width: 100%;\n height: var(--input-height);\n border-radius: var(--uui-border-radius);\n }\n\n uui-button {\n width: 100%;\n margin-top: var(--uui-size-space-5);\n --uui-button-padding-top-factor: 1.5;\n --uui-button-padding-bottom-factor: 1.5;\n }\n\n .text-danger {\n color: var(--uui-color-danger-standalone);\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'umb-new-password-layout': UmbNewPasswordLayoutElement;\n }\n}\n","import { CSSResultGroup, LitElement, css, html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\n@customElement('umb-confirmation-layout')\nexport default class UmbConfirmationLayoutElement extends LitElement {\n @property({ type: String })\n header = '';\n\n @property({ type: String })\n message = '';\n\n render() {\n return html`\n \n\n \n\n \n `;\n }\n\n static styles: CSSResultGroup = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n gap: var(--uui-size-layout-1);\n }\n\n #header {\n text-align: center;\n display: flex;\n flex-direction: column;\n gap: var(--uui-size-space-5);\n }\n\n #header span {\n color: var(--uui-color-text-alt); /* TODO Change to uui color when uui gets a muted text variable */\n font-size: 14px;\n }\n\n #header h1 {\n margin: 0;\n font-weight: 400;\n font-size: var(--header-secondary-font-size);\n color: var(--uui-color-interactive);\n line-height: 1.2;\n }\n\n uui-button {\n width: 100%;\n margin-top: var(--uui-size-space-5);\n --uui-button-padding-top-factor: 1.5;\n --uui-button-padding-bottom-factor: 1.5;\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'umb-confirmation-layout': UmbConfirmationLayoutElement;\n }\n}\n","import { CSSResultGroup, LitElement, css, html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\n@customElement('umb-error-layout')\nexport default class UmbErrorLayoutElement extends LitElement {\n @property({ type: String })\n header = '';\n\n @property({ type: String })\n message = '';\n\n render() {\n return html`\n \n \n \n `;\n }\n\n static styles: CSSResultGroup = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n gap: var(--uui-size-layout-1);\n }\n\n #header {\n text-align: center;\n display: flex;\n flex-direction: column;\n gap: var(--uui-size-space-5);\n }\n\n #header span {\n color: var(--uui-color-text-alt); /* TODO Change to uui color when uui gets a muted text variable */\n font-size: 14px;\n }\n\n #header h1 {\n margin: 0;\n font-weight: 400;\n font-size: var(--header-secondary-font-size);\n color: var(--uui-color-interactive);\n line-height: 1.2;\n }\n\n ::slotted(uui-button) {\n width: 100%;\n margin-top: var(--uui-size-space-5);\n --uui-button-padding-top-factor: 1.5;\n --uui-button-padding-bottom-factor: 1.5;\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'umb-error-layout': UmbErrorLayoutElement;\n }\n}\n","import { UUIIconRegistry, UUIIconRegistryElement, UUIIconRegistryEssential } from '@umbraco-ui/uui';\nimport { Observable, ReplaySubject } from 'rxjs';\nimport { customElement } from 'lit/decorators.js';\n\n/**\n * This is a custom icon registry that will load icons from the Umbraco assets folder.\n * Optimistically, we will provide the icon, and then try and load it.\n */\nclass UmbIconRegistry extends UUIIconRegistry {\n\tprotected acceptIcon(iconName: string): boolean {\n // If the icon name is a variable, we will not provide it.\n if (iconName.startsWith('{{') && iconName.endsWith('}}')) {\n return false;\n }\n\n\t\t// Inform that we will be providing this.\n\t\tconst icon = this.provideIcon(iconName);\n\n\t\tthis.#getIcons().subscribe((icons) => {\n\t\t\tif (icons[iconName]) {\n\t\t\t\ticon.svg = icons[iconName].replace('