valtech-components 4.0.120 → 4.0.121

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,4 +32,4 @@ export const DEFAULT_LOGIN_LOGO = {
32
32
  flex: true,
33
33
  width: 4,
34
34
  };
35
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvb3JnYW5pc21zL2xvZ2luL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWtGQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FFdkI7SUFDRixTQUFTLEVBQUUsSUFBSTtJQUNmLGNBQWMsRUFBRSxDQUFDLFFBQVEsQ0FBQztJQUMxQixZQUFZLEVBQUUsSUFBSTtJQUNsQixrQkFBa0IsRUFBRSxJQUFJO0lBQ3hCLFFBQVEsRUFBRSxLQUFLO0NBQ2hCLENBQUM7QUFFRjs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBa0I7SUFDL0MsR0FBRyxFQUFFLGtCQUFrQjtJQUN2QixHQUFHLEVBQUUsRUFBRTtJQUNQLElBQUksRUFBRSxLQUFLO0lBQ1gsTUFBTSxFQUFFLEtBQUs7SUFDYixRQUFRLEVBQUUsS0FBSztJQUNmLElBQUksRUFBRSxRQUFRO0lBQ2QsU0FBUyxFQUFFLFFBQVE7SUFDbkIsSUFBSSxFQUFFLElBQUk7SUFDVixLQUFLLEVBQUUsQ0FBQztDQUNULENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbWFnZU1ldGFkYXRhIH0gZnJvbSAnLi4vLi4vYXRvbXMvaW1hZ2UvdHlwZXMnO1xuaW1wb3J0IHsgT0F1dGhQcm92aWRlciB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL2F1dGgvdHlwZXMnO1xuaW1wb3J0IHsgQXV0aFVzZXIgfSBmcm9tICcuLi8uLi8uLi9zZXJ2aWNlcy9hdXRoL3R5cGVzJztcblxuLyoqXG4gKiBDb25maWd1cmF0aW9uIGZvciBsZWdhbCBub3RpY2UgZGlzcGxheWVkIGluIHRoZSBsb2dpbiBjb21wb25lbnRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMb2dpbkxlZ2FsQ29uZmlnIHtcbiAgLyoqIENvbXBhbnkgbmFtZSB0byBkaXNwbGF5ICovXG4gIGNvbXBhbnlOYW1lOiBzdHJpbmc7XG4gIC8qKiBMaW5rIGZvciBjb21wYW55IG5hbWUgKG9wdGlvbmFsKSAqL1xuICBjb21wYW55TGluaz86IHN0cmluZztcbiAgLyoqIExpbmsgdG8gdGVybXMgYW5kIGNvbmRpdGlvbnMgcGFnZSAqL1xuICB0ZXJtc0xpbms/OiBzdHJpbmc7XG4gIC8qKiBMaW5rIHRvIHByaXZhY3kgcG9saWN5IHBhZ2UgKi9cbiAgcHJpdmFjeUxpbms/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogTWFpbiBjb25maWd1cmF0aW9uIGZvciB0aGUgTG9naW4gY29tcG9uZW50XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTG9naW5NZXRhZGF0YSB7XG4gIC8qKiBMb2dvIHRvIGRpc3BsYXkgYXQgdGhlIHRvcCBvZiB0aGUgZm9ybSAqL1xuICBsb2dvPzogSW1hZ2VNZXRhZGF0YTtcblxuICAvKiogU2hvdyBPQXV0aCBsb2dpbiBidXR0b25zIChkZWZhdWx0OiB0cnVlKSAqL1xuICBzaG93T0F1dGg/OiBib29sZWFuO1xuXG4gIC8qKiBPQXV0aCBwcm92aWRlcnMgdG8gc2hvdyAoZGVmYXVsdDogWydnb29nbGUnXSkgKi9cbiAgb2F1dGhQcm92aWRlcnM/OiBPQXV0aFByb3ZpZGVyW107XG5cbiAgLyoqIFNob3cgcmVnaXN0ZXIgbGluayBhbmQgbW9kYWwgKGRlZmF1bHQ6IHRydWUpICovXG4gIHNob3dSZWdpc3Rlcj86IGJvb2xlYW47XG5cbiAgLyoqIFNob3cgZm9yZ290IHBhc3N3b3JkIGxpbmsgYW5kIG1vZGFsIChkZWZhdWx0OiB0cnVlKSAqL1xuICBzaG93Rm9yZ290UGFzc3dvcmQ/OiBib29sZWFuO1xuXG4gIC8qKiBXcmFwIGNvbXBvbmVudCBpbiBjYXJkLXN0eWxlIGNvbnRhaW5lciB3aXRoIGJhY2tncm91bmQsIHNoYWRvdywgcm91bmRlZCBjb3JuZXJzIChkZWZhdWx0OiBmYWxzZSkgKi9cbiAgc2hvd0NhcmQ/OiBib29sZWFuO1xuXG4gIC8qKiBMZWdhbCBub3RpY2UgY29uZmlndXJhdGlvbiAqL1xuICBsZWdhbD86IExvZ2luTGVnYWxDb25maWc7XG5cbiAgLyoqIFJvdXRlIHRvIHJlZGlyZWN0IGFmdGVyIHN1Y2Nlc3NmdWwgbG9naW4gKG9wdGlvbmFsIC0gaWYgbm90IHNldCwgZW1pdHMgZXZlbnQpICovXG4gIHJlZGlyZWN0T25TdWNjZXNzPzogc3RyaW5nO1xuXG4gIC8qKiBPcGVuIGRpcmVjdGx5IGluIHNpZ251cCB2aWV3IChkZWZhdWx0OiAnc2lnbmluJykgKi9cbiAgaW5pdGlhbE9wZXJhdGlvbj86ICdzaWduaW4nIHwgJ3NpZ251cCc7XG59XG5cbi8qKlxuICogRXZlbnQgZW1pdHRlZCB3aGVuIGxvZ2luIGlzIHN1Y2Nlc3NmdWxcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMb2dpblN1Y2Nlc3NFdmVudCB7XG4gIC8qKiBUaGUgYXV0aGVudGljYXRlZCB1c2VyICovXG4gIHVzZXI6IEF1dGhVc2VyIHwgbnVsbDtcbiAgLyoqIFdoZXRoZXIgTUZBIHdhcyByZXF1aXJlZCBhbmQgY29tcGxldGVkICovXG4gIG1mYUNvbXBsZXRlZD86IGJvb2xlYW47XG4gIC8qKiBXaGV0aGVyIHRoaXMgd2FzIGFuIE9BdXRoIGxvZ2luICovXG4gIG9hdXRoUHJvdmlkZXI/OiBPQXV0aFByb3ZpZGVyO1xufVxuXG4vKipcbiAqIEV2ZW50IGVtaXR0ZWQgd2hlbiBsb2dpbiBmYWlsc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIExvZ2luRXJyb3JFdmVudCB7XG4gIC8qKiBFcnJvciBjb2RlIGZyb20gdGhlIGJhY2tlbmQgKi9cbiAgY29kZT86IHN0cmluZztcbiAgLyoqIEh1bWFuLXJlYWRhYmxlIGVycm9yIG1lc3NhZ2UgKi9cbiAgbWVzc2FnZTogc3RyaW5nO1xuICAvKiogVGhlIG9wZXJhdGlvbiB0aGF0IGZhaWxlZCAqL1xuICBvcGVyYXRpb246ICdzaWduaW4nIHwgJ3NpZ251cCcgfCAndmVyaWZ5JyB8ICdmb3Jnb3QnIHwgJ3Jlc2V0JyB8ICdtZmEnIHwgJ29hdXRoJztcbn1cblxuLyoqXG4gKiBFdmVudCBlbWl0dGVkIHdoZW4gTUZBIHZlcmlmaWNhdGlvbiBpcyByZXF1aXJlZFxuICovXG5leHBvcnQgaW50ZXJmYWNlIE1GQVJlcXVpcmVkRXZlbnQge1xuICAvKiogTUZBIG1ldGhvZCByZXF1aXJlZCAqL1xuICBtZXRob2Q6ICdUT1RQJyB8ICdFTUFJTCcgfCAnU01TJztcbn1cblxuLyoqXG4gKiBEZWZhdWx0IHZhbHVlcyBmb3IgTG9naW5NZXRhZGF0YVxuICovXG5leHBvcnQgY29uc3QgTE9HSU5fREVGQVVMVFM6IFJlcXVpcmVkPFxuICBPbWl0PExvZ2luTWV0YWRhdGEsICdsb2dvJyB8ICdsZWdhbCcgfCAncmVkaXJlY3RPblN1Y2Nlc3MnIHwgJ2luaXRpYWxPcGVyYXRpb24nPlxuPiA9IHtcbiAgc2hvd09BdXRoOiB0cnVlLFxuICBvYXV0aFByb3ZpZGVyczogWydnb29nbGUnXSxcbiAgc2hvd1JlZ2lzdGVyOiB0cnVlLFxuICBzaG93Rm9yZ290UGFzc3dvcmQ6IHRydWUsXG4gIHNob3dDYXJkOiBmYWxzZSxcbn07XG5cbi8qKlxuICogTG9nbyBwb3IgZGVmZWN0byBkZSBsYSBjYXJkIGRlIGxvZ2luIGN1YW5kbyBlbCBjb25zdW1lciBubyBwYXNhIGBsb2dvYC5cbiAqXG4gKiBVc2EgZWwgdG9rZW4gQ1NTIGAtLW1haW4tbG9nby1taW5pYCAoZWwgbG9nbyBNSU5JL2ljb25vLCBlbCBtaXNtbyBxdWUgZWxcbiAqIHNpZGUgbWVudSBgdmFsLW1lbnVgKSwgcmVzdWVsdG8gcG9yIGB2YWwtaW1hZ2VgIHbDrWEgYHZhcigtLW1haW4tbG9nby1taW5pKWAuXG4gKiBDYWRhIGFwcCBkZWwgZmFjdG9yeSBsbyBkZWZpbmUgZW4gc3UgYHRoZW1lL3ZhcmlhYmxlcy5zY3NzYCAoc2hvd2Nhc2Ug4oaSXG4gKiBgbWFpbi1pY29uLnBuZ2AsIGJpbmdvIOKGkiBgZmF2aWNvbi1iYWxscy5zdmdgKS4gTk8gZXMgZWwgbG9ja3VwIGdyYW5kZVxuICogYC0tbWFpbi1sb2dvYCBkZWwgaGVhZGVyLiBBc8OtIGVsIGxvZ2luIG11ZXN0cmEgU0lFTVBSRSBlbCBpY29ubyBkZSBtYXJjYSBkZVxuICogbGEgYXBwIHNpbiBhY29wbGFyIGxhIGxpYiBhIHVuYSBtYXJjYSBjb25jcmV0YSDigJQgZXMgZWwgZXN0w6FuZGFyIGRlbCBmYWN0b3J5LlxuICpcbiAqIFVuYSBhcHAgcHVlZGUgb3ZlcnJpZGUgcGFzYW5kbyBzdSBwcm9waW8gYGxvZ29gIGVuIGBMb2dpbk1ldGFkYXRhYCAoZWouXG4gKiBzaG93Y2FzZSB1c2EgdW4gbWFyayBwcm9waW8gYHRlcm1pbmFsLnN2Z2ApLlxuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9MT0dJTl9MT0dPOiBJbWFnZU1ldGFkYXRhID0ge1xuICBzcmM6ICctLW1haW4tbG9nby1taW5pJyxcbiAgYWx0OiAnJyxcbiAgbW9kZTogJ2JveCcsXG4gIHNoYWRlZDogZmFsc2UsXG4gIGJvcmRlcmVkOiBmYWxzZSxcbiAgc2l6ZTogJ3hsYXJnZScsXG4gIGFsaWdubWVudDogJ2NlbnRlcicsXG4gIGZsZXg6IHRydWUsXG4gIHdpZHRoOiA0LFxufTtcbiJdfQ==
35
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvb3JnYW5pc21zL2xvZ2luL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTJGQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FFdkI7SUFDRixTQUFTLEVBQUUsSUFBSTtJQUNmLGNBQWMsRUFBRSxDQUFDLFFBQVEsQ0FBQztJQUMxQixZQUFZLEVBQUUsSUFBSTtJQUNsQixrQkFBa0IsRUFBRSxJQUFJO0lBQ3hCLFFBQVEsRUFBRSxLQUFLO0NBQ2hCLENBQUM7QUFFRjs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBa0I7SUFDL0MsR0FBRyxFQUFFLGtCQUFrQjtJQUN2QixHQUFHLEVBQUUsRUFBRTtJQUNQLElBQUksRUFBRSxLQUFLO0lBQ1gsTUFBTSxFQUFFLEtBQUs7SUFDYixRQUFRLEVBQUUsS0FBSztJQUNmLElBQUksRUFBRSxRQUFRO0lBQ2QsU0FBUyxFQUFFLFFBQVE7SUFDbkIsSUFBSSxFQUFFLElBQUk7SUFDVixLQUFLLEVBQUUsQ0FBQztDQUNULENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbWFnZU1ldGFkYXRhIH0gZnJvbSAnLi4vLi4vYXRvbXMvaW1hZ2UvdHlwZXMnO1xuaW1wb3J0IHsgT0F1dGhQcm92aWRlciB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL2F1dGgvdHlwZXMnO1xuaW1wb3J0IHsgQXV0aFVzZXIgfSBmcm9tICcuLi8uLi8uLi9zZXJ2aWNlcy9hdXRoL3R5cGVzJztcblxuLyoqXG4gKiBDb25maWd1cmF0aW9uIGZvciBsZWdhbCBub3RpY2UgZGlzcGxheWVkIGluIHRoZSBsb2dpbiBjb21wb25lbnRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMb2dpbkxlZ2FsQ29uZmlnIHtcbiAgLyoqIENvbXBhbnkgbmFtZSB0byBkaXNwbGF5ICovXG4gIGNvbXBhbnlOYW1lOiBzdHJpbmc7XG4gIC8qKiBMaW5rIGZvciBjb21wYW55IG5hbWUgKG9wdGlvbmFsKSAqL1xuICBjb21wYW55TGluaz86IHN0cmluZztcbiAgLyoqIExpbmsgdG8gdGVybXMgYW5kIGNvbmRpdGlvbnMgcGFnZSAqL1xuICB0ZXJtc0xpbms/OiBzdHJpbmc7XG4gIC8qKiBMaW5rIHRvIHByaXZhY3kgcG9saWN5IHBhZ2UgKi9cbiAgcHJpdmFjeUxpbms/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogTWFpbiBjb25maWd1cmF0aW9uIGZvciB0aGUgTG9naW4gY29tcG9uZW50XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTG9naW5NZXRhZGF0YSB7XG4gIC8qKiBMb2dvIHRvIGRpc3BsYXkgYXQgdGhlIHRvcCBvZiB0aGUgZm9ybSAqL1xuICBsb2dvPzogSW1hZ2VNZXRhZGF0YTtcblxuICAvKiogU2hvdyBPQXV0aCBsb2dpbiBidXR0b25zIChkZWZhdWx0OiB0cnVlKSAqL1xuICBzaG93T0F1dGg/OiBib29sZWFuO1xuXG4gIC8qKiBPQXV0aCBwcm92aWRlcnMgdG8gc2hvdyAoZGVmYXVsdDogWydnb29nbGUnXSkgKi9cbiAgb2F1dGhQcm92aWRlcnM/OiBPQXV0aFByb3ZpZGVyW107XG5cbiAgLyoqIFNob3cgcmVnaXN0ZXIgbGluayBhbmQgbW9kYWwgKGRlZmF1bHQ6IHRydWUpICovXG4gIHNob3dSZWdpc3Rlcj86IGJvb2xlYW47XG5cbiAgLyoqIFNob3cgZm9yZ290IHBhc3N3b3JkIGxpbmsgYW5kIG1vZGFsIChkZWZhdWx0OiB0cnVlKSAqL1xuICBzaG93Rm9yZ290UGFzc3dvcmQ/OiBib29sZWFuO1xuXG4gIC8qKiBXcmFwIGNvbXBvbmVudCBpbiBjYXJkLXN0eWxlIGNvbnRhaW5lciB3aXRoIGJhY2tncm91bmQsIHNoYWRvdywgcm91bmRlZCBjb3JuZXJzIChkZWZhdWx0OiBmYWxzZSkgKi9cbiAgc2hvd0NhcmQ/OiBib29sZWFuO1xuXG4gIC8qKiBMZWdhbCBub3RpY2UgY29uZmlndXJhdGlvbiAqL1xuICBsZWdhbD86IExvZ2luTGVnYWxDb25maWc7XG5cbiAgLyoqIFJvdXRlIHRvIHJlZGlyZWN0IGFmdGVyIHN1Y2Nlc3NmdWwgbG9naW4gKG9wdGlvbmFsIC0gaWYgbm90IHNldCwgZW1pdHMgZXZlbnQpICovXG4gIHJlZGlyZWN0T25TdWNjZXNzPzogc3RyaW5nO1xuXG4gIC8qKiBPcGVuIGRpcmVjdGx5IGluIHNpZ251cCB2aWV3IChkZWZhdWx0OiAnc2lnbmluJykgKi9cbiAgaW5pdGlhbE9wZXJhdGlvbj86ICdzaWduaW4nIHwgJ3NpZ251cCc7XG5cbiAgLyoqXG4gICAqIFJ1dGEgZGUgbGEgcMOhZ2luYSBkZSBsb2dpbi4gU2kgc2Ugc2V0ZWEsIGVsIGxpbmsgXCLCv1lhIHRpZW5lcyBjdWVudGE/XCIgZGVsXG4gICAqIG1vZGFsIGRlIHJlZ2lzdHJvIE5BVkVHQSBhIGVzYSBydXRhIChjaWVycmEgZWwgbW9kYWwgeSBsdWVnbyBlbnJ1dGEpIGVuIHZlelxuICAgKiBkZSBzb2xvIGNlcnJhciBlbCBtb2RhbC4gw5p0aWwgY3VhbmRvIGVsIGB2YWwtbG9naW5gIHNlIHVzYSBzb2xvIGNvbW8gbW9kYWxcbiAgICogZGUgcmVnaXN0cm8gKGVqLiBsYW5kaW5nKSB5IGVsIGxvZ2luIHJlYWwgdml2ZSBlbiB1bmEgcMOhZ2luYSBhcGFydGUuXG4gICAqIFNpbiBzZXRlYXIg4oaSIGNvbXBvcnRhbWllbnRvIHBvciBkZWZlY3RvOiBlbCBsaW5rIHNvbG8gY2llcnJhIGVsIG1vZGFsLlxuICAgKi9cbiAgbG9naW5Sb3V0ZT86IHN0cmluZztcbn1cblxuLyoqXG4gKiBFdmVudCBlbWl0dGVkIHdoZW4gbG9naW4gaXMgc3VjY2Vzc2Z1bFxuICovXG5leHBvcnQgaW50ZXJmYWNlIExvZ2luU3VjY2Vzc0V2ZW50IHtcbiAgLyoqIFRoZSBhdXRoZW50aWNhdGVkIHVzZXIgKi9cbiAgdXNlcjogQXV0aFVzZXIgfCBudWxsO1xuICAvKiogV2hldGhlciBNRkEgd2FzIHJlcXVpcmVkIGFuZCBjb21wbGV0ZWQgKi9cbiAgbWZhQ29tcGxldGVkPzogYm9vbGVhbjtcbiAgLyoqIFdoZXRoZXIgdGhpcyB3YXMgYW4gT0F1dGggbG9naW4gKi9cbiAgb2F1dGhQcm92aWRlcj86IE9BdXRoUHJvdmlkZXI7XG59XG5cbi8qKlxuICogRXZlbnQgZW1pdHRlZCB3aGVuIGxvZ2luIGZhaWxzXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTG9naW5FcnJvckV2ZW50IHtcbiAgLyoqIEVycm9yIGNvZGUgZnJvbSB0aGUgYmFja2VuZCAqL1xuICBjb2RlPzogc3RyaW5nO1xuICAvKiogSHVtYW4tcmVhZGFibGUgZXJyb3IgbWVzc2FnZSAqL1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIC8qKiBUaGUgb3BlcmF0aW9uIHRoYXQgZmFpbGVkICovXG4gIG9wZXJhdGlvbjogJ3NpZ25pbicgfCAnc2lnbnVwJyB8ICd2ZXJpZnknIHwgJ2ZvcmdvdCcgfCAncmVzZXQnIHwgJ21mYScgfCAnb2F1dGgnO1xufVxuXG4vKipcbiAqIEV2ZW50IGVtaXR0ZWQgd2hlbiBNRkEgdmVyaWZpY2F0aW9uIGlzIHJlcXVpcmVkXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTUZBUmVxdWlyZWRFdmVudCB7XG4gIC8qKiBNRkEgbWV0aG9kIHJlcXVpcmVkICovXG4gIG1ldGhvZDogJ1RPVFAnIHwgJ0VNQUlMJyB8ICdTTVMnO1xufVxuXG4vKipcbiAqIERlZmF1bHQgdmFsdWVzIGZvciBMb2dpbk1ldGFkYXRhXG4gKi9cbmV4cG9ydCBjb25zdCBMT0dJTl9ERUZBVUxUUzogUmVxdWlyZWQ8XG4gIE9taXQ8TG9naW5NZXRhZGF0YSwgJ2xvZ28nIHwgJ2xlZ2FsJyB8ICdyZWRpcmVjdE9uU3VjY2VzcycgfCAnaW5pdGlhbE9wZXJhdGlvbicgfCAnbG9naW5Sb3V0ZSc+XG4+ID0ge1xuICBzaG93T0F1dGg6IHRydWUsXG4gIG9hdXRoUHJvdmlkZXJzOiBbJ2dvb2dsZSddLFxuICBzaG93UmVnaXN0ZXI6IHRydWUsXG4gIHNob3dGb3Jnb3RQYXNzd29yZDogdHJ1ZSxcbiAgc2hvd0NhcmQ6IGZhbHNlLFxufTtcblxuLyoqXG4gKiBMb2dvIHBvciBkZWZlY3RvIGRlIGxhIGNhcmQgZGUgbG9naW4gY3VhbmRvIGVsIGNvbnN1bWVyIG5vIHBhc2EgYGxvZ29gLlxuICpcbiAqIFVzYSBlbCB0b2tlbiBDU1MgYC0tbWFpbi1sb2dvLW1pbmlgIChlbCBsb2dvIE1JTkkvaWNvbm8sIGVsIG1pc21vIHF1ZSBlbFxuICogc2lkZSBtZW51IGB2YWwtbWVudWApLCByZXN1ZWx0byBwb3IgYHZhbC1pbWFnZWAgdsOtYSBgdmFyKC0tbWFpbi1sb2dvLW1pbmkpYC5cbiAqIENhZGEgYXBwIGRlbCBmYWN0b3J5IGxvIGRlZmluZSBlbiBzdSBgdGhlbWUvdmFyaWFibGVzLnNjc3NgIChzaG93Y2FzZSDihpJcbiAqIGBtYWluLWljb24ucG5nYCwgYmluZ28g4oaSIGBmYXZpY29uLWJhbGxzLnN2Z2ApLiBOTyBlcyBlbCBsb2NrdXAgZ3JhbmRlXG4gKiBgLS1tYWluLWxvZ29gIGRlbCBoZWFkZXIuIEFzw60gZWwgbG9naW4gbXVlc3RyYSBTSUVNUFJFIGVsIGljb25vIGRlIG1hcmNhIGRlXG4gKiBsYSBhcHAgc2luIGFjb3BsYXIgbGEgbGliIGEgdW5hIG1hcmNhIGNvbmNyZXRhIOKAlCBlcyBlbCBlc3TDoW5kYXIgZGVsIGZhY3RvcnkuXG4gKlxuICogVW5hIGFwcCBwdWVkZSBvdmVycmlkZSBwYXNhbmRvIHN1IHByb3BpbyBgbG9nb2AgZW4gYExvZ2luTWV0YWRhdGFgIChlai5cbiAqIHNob3djYXNlIHVzYSB1biBtYXJrIHByb3BpbyBgdGVybWluYWwuc3ZnYCkuXG4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX0xPR0lOX0xPR086IEltYWdlTWV0YWRhdGEgPSB7XG4gIHNyYzogJy0tbWFpbi1sb2dvLW1pbmknLFxuICBhbHQ6ICcnLFxuICBtb2RlOiAnYm94JyxcbiAgc2hhZGVkOiBmYWxzZSxcbiAgYm9yZGVyZWQ6IGZhbHNlLFxuICBzaXplOiAneGxhcmdlJyxcbiAgYWxpZ25tZW50OiAnY2VudGVyJyxcbiAgZmxleDogdHJ1ZSxcbiAgd2lkdGg6IDQsXG59O1xuIl19
@@ -2,5 +2,5 @@
2
2
  * Current version of valtech-components.
3
3
  * This is automatically updated during the publish process.
4
4
  */
5
- export const VERSION = '4.0.120';
6
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvdmVyc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDdXJyZW50IHZlcnNpb24gb2YgdmFsdGVjaC1jb21wb25lbnRzLlxuICogVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHVwZGF0ZWQgZHVyaW5nIHRoZSBwdWJsaXNoIHByb2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gJzQuMC4xMjAnO1xuIl19
5
+ export const VERSION = '4.0.121';
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvdmVyc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDdXJyZW50IHZlcnNpb24gb2YgdmFsdGVjaC1jb21wb25lbnRzLlxuICogVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHVwZGF0ZWQgZHVyaW5nIHRoZSBwdWJsaXNoIHByb2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gJzQuMC4xMjEnO1xuIl19
@@ -56,7 +56,7 @@ import { BrowserMultiFormatReader } from '@zxing/browser';
56
56
  * Current version of valtech-components.
57
57
  * This is automatically updated during the publish process.
58
58
  */
59
- const VERSION = '4.0.120';
59
+ const VERSION = '4.0.121';
60
60
 
61
61
  // Control de estado de refresco (singleton a nivel de módulo)
62
62
  let isRefreshing = false;
@@ -41589,6 +41589,11 @@ class LoginComponent {
41589
41589
  state: this._resetPasswordFormState(),
41590
41590
  });
41591
41591
  });
41592
+ // ==========================================
41593
+ // REGISTER HANDLERS
41594
+ // ==========================================
41595
+ /** Navegación pendiente a la página de login tras cerrar el modal de registro. */
41596
+ this._pendingLoginNav = false;
41592
41597
  }
41593
41598
  /** URL del sitio principal resuelta por ambiente — fallback cuando el consumer no pasa companyLink. */
41594
41599
  get resolvedCompanyLink() {
@@ -41665,14 +41670,34 @@ class LoginComponent {
41665
41670
  },
41666
41671
  });
41667
41672
  }
41668
- // ==========================================
41669
- // REGISTER HANDLERS
41670
- // ==========================================
41671
41673
  openRegisterModal() {
41672
41674
  this.isRegisterModalOpen = true;
41673
41675
  }
41674
41676
  closeRegisterModal() {
41675
41677
  this.isRegisterModalOpen = false;
41678
+ // Navegación diferida: se hace en el cierre del modal (didDismiss llama acá)
41679
+ // para que ion-modal complete su animación antes de enrutar — sin esto el
41680
+ // modal puede quedar visible sobre la página destino.
41681
+ if (this._pendingLoginNav) {
41682
+ this._pendingLoginNav = false;
41683
+ const route = this.props.loginRoute;
41684
+ if (route)
41685
+ this.router.navigate([route]);
41686
+ }
41687
+ }
41688
+ /**
41689
+ * Link "¿Ya tienes cuenta?" del modal de registro. Si `props.loginRoute` está
41690
+ * configurado, cierra el modal y navega a la página de login; si no, solo
41691
+ * cierra el modal (comportamiento por defecto).
41692
+ */
41693
+ onRegisterSwitchToLogin() {
41694
+ if (this.props.loginRoute) {
41695
+ this._pendingLoginNav = true;
41696
+ this.isRegisterModalOpen = false; // dispara (didDismiss) → closeRegisterModal
41697
+ }
41698
+ else {
41699
+ this.closeRegisterModal();
41700
+ }
41676
41701
  }
41677
41702
  registerHandler(event) {
41678
41703
  const name = event.fields['name'];
@@ -42034,7 +42059,7 @@ class LoginComponent {
42034
42059
  this.stopResetResendCooldown();
42035
42060
  }
42036
42061
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LoginComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
42037
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LoginComponent, isStandalone: true, selector: "val-login", inputs: { props: "props" }, outputs: { onSuccess: "onSuccess", onError: "onError", onMFARequired: "onMFARequired" }, ngImport: i0, template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo \u2014 default de marca (--main-logo) si el consumer no pasa logo -->\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"dark\"\n (click)=\"loginWithOAuth(provider)\"\n [disabled]=\"isOAuthLoading\"\n >\n @switch (provider) { @case ('google') {\n <ion-icon slot=\"start\" name=\"logo-google\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithGoogle') }} } @case ('apple') {\n <ion-icon slot=\"start\" name=\"logo-apple\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithApple') }} } @case ('microsoft') {\n <ion-icon slot=\"start\" name=\"logo-microsoft\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithMicrosoft') }} } }\n </ion-button>\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (resolvedCompanyLink) {\n <a [href]=\"resolvedCompanyLink\" target=\"_blank\" rel=\"noopener noreferrer\"\n ><strong>{{ props.legal.companyName }}</strong></a\n >\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeRegisterModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"closeRegisterModal()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeVerifyModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeForgotPasswordModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeResetPasswordModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAVerifyModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n @if (mfaMethod() === 'TOTP') {\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n @if (mfaUseBackupCode()) {\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseTotpAction') }}</a>\n } @else { {{ t('mfaUseBackupLink') }}\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseBackupAction') }}</a>\n }\n </ion-text>\n </div>\n }\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('mfaLostBackupLink') }}\n <a (click)=\"openMFAResetModal()\">{{ t('mfaResetAction') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Reset Modal (B) \u2014 recovery por email cuando no hay backup codes -->\n<ion-modal [isOpen]=\"isMFAResetModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"closeMFAResetModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAResetModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n @if (mfaResetStep() === 'request') {\n <val-form [props]=\"mfaResetRequestFormProps()\" (onSubmit)=\"mfaResetRequestHandler($event)\" />\n } @else {\n <val-form [props]=\"mfaResetConfirmFormProps()\" (onSubmit)=\"mfaResetConfirmHandler($event)\" />\n }\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem}.oauth-buttons ion-button{--border-radius: 8px;--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: FormComponent, selector: "val-form", inputs: ["props"], outputs: ["onSubmit", "onInvalid", "onSelectChange"] }, { kind: "component", type: ImageComponent, selector: "val-image", inputs: ["props"] }] }); }
42062
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LoginComponent, isStandalone: true, selector: "val-login", inputs: { props: "props" }, outputs: { onSuccess: "onSuccess", onError: "onError", onMFARequired: "onMFARequired" }, ngImport: i0, template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo \u2014 default de marca (--main-logo) si el consumer no pasa logo -->\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"dark\"\n (click)=\"loginWithOAuth(provider)\"\n [disabled]=\"isOAuthLoading\"\n >\n @switch (provider) { @case ('google') {\n <ion-icon slot=\"start\" name=\"logo-google\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithGoogle') }} } @case ('apple') {\n <ion-icon slot=\"start\" name=\"logo-apple\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithApple') }} } @case ('microsoft') {\n <ion-icon slot=\"start\" name=\"logo-microsoft\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithMicrosoft') }} } }\n </ion-button>\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (resolvedCompanyLink) {\n <a [href]=\"resolvedCompanyLink\" target=\"_blank\" rel=\"noopener noreferrer\"\n ><strong>{{ props.legal.companyName }}</strong></a\n >\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeRegisterModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"onRegisterSwitchToLogin()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeVerifyModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeForgotPasswordModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeResetPasswordModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAVerifyModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n @if (mfaMethod() === 'TOTP') {\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n @if (mfaUseBackupCode()) {\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseTotpAction') }}</a>\n } @else { {{ t('mfaUseBackupLink') }}\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseBackupAction') }}</a>\n }\n </ion-text>\n </div>\n }\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('mfaLostBackupLink') }}\n <a (click)=\"openMFAResetModal()\">{{ t('mfaResetAction') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Reset Modal (B) \u2014 recovery por email cuando no hay backup codes -->\n<ion-modal [isOpen]=\"isMFAResetModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"closeMFAResetModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAResetModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n @if (mfaResetStep() === 'request') {\n <val-form [props]=\"mfaResetRequestFormProps()\" (onSubmit)=\"mfaResetRequestHandler($event)\" />\n } @else {\n <val-form [props]=\"mfaResetConfirmFormProps()\" (onSubmit)=\"mfaResetConfirmHandler($event)\" />\n }\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem}.oauth-buttons ion-button{--border-radius: 8px;--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: FormComponent, selector: "val-form", inputs: ["props"], outputs: ["onSubmit", "onInvalid", "onSelectChange"] }, { kind: "component", type: ImageComponent, selector: "val-image", inputs: ["props"] }] }); }
42038
42063
  }
42039
42064
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LoginComponent, decorators: [{
42040
42065
  type: Component,
@@ -42050,7 +42075,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
42050
42075
  IonToolbar,
42051
42076
  FormComponent,
42052
42077
  ImageComponent,
42053
- ], template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo \u2014 default de marca (--main-logo) si el consumer no pasa logo -->\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"dark\"\n (click)=\"loginWithOAuth(provider)\"\n [disabled]=\"isOAuthLoading\"\n >\n @switch (provider) { @case ('google') {\n <ion-icon slot=\"start\" name=\"logo-google\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithGoogle') }} } @case ('apple') {\n <ion-icon slot=\"start\" name=\"logo-apple\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithApple') }} } @case ('microsoft') {\n <ion-icon slot=\"start\" name=\"logo-microsoft\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithMicrosoft') }} } }\n </ion-button>\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (resolvedCompanyLink) {\n <a [href]=\"resolvedCompanyLink\" target=\"_blank\" rel=\"noopener noreferrer\"\n ><strong>{{ props.legal.companyName }}</strong></a\n >\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeRegisterModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"closeRegisterModal()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeVerifyModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeForgotPasswordModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeResetPasswordModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAVerifyModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n @if (mfaMethod() === 'TOTP') {\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n @if (mfaUseBackupCode()) {\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseTotpAction') }}</a>\n } @else { {{ t('mfaUseBackupLink') }}\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseBackupAction') }}</a>\n }\n </ion-text>\n </div>\n }\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('mfaLostBackupLink') }}\n <a (click)=\"openMFAResetModal()\">{{ t('mfaResetAction') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Reset Modal (B) \u2014 recovery por email cuando no hay backup codes -->\n<ion-modal [isOpen]=\"isMFAResetModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"closeMFAResetModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAResetModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n @if (mfaResetStep() === 'request') {\n <val-form [props]=\"mfaResetRequestFormProps()\" (onSubmit)=\"mfaResetRequestHandler($event)\" />\n } @else {\n <val-form [props]=\"mfaResetConfirmFormProps()\" (onSubmit)=\"mfaResetConfirmHandler($event)\" />\n }\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem}.oauth-buttons ion-button{--border-radius: 8px;--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"] }]
42078
+ ], template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo \u2014 default de marca (--main-logo) si el consumer no pasa logo -->\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"dark\"\n (click)=\"loginWithOAuth(provider)\"\n [disabled]=\"isOAuthLoading\"\n >\n @switch (provider) { @case ('google') {\n <ion-icon slot=\"start\" name=\"logo-google\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithGoogle') }} } @case ('apple') {\n <ion-icon slot=\"start\" name=\"logo-apple\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithApple') }} } @case ('microsoft') {\n <ion-icon slot=\"start\" name=\"logo-microsoft\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithMicrosoft') }} } }\n </ion-button>\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (resolvedCompanyLink) {\n <a [href]=\"resolvedCompanyLink\" target=\"_blank\" rel=\"noopener noreferrer\"\n ><strong>{{ props.legal.companyName }}</strong></a\n >\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeRegisterModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"onRegisterSwitchToLogin()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeVerifyModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeForgotPasswordModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeResetPasswordModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAVerifyModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n @if (mfaMethod() === 'TOTP') {\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n @if (mfaUseBackupCode()) {\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseTotpAction') }}</a>\n } @else { {{ t('mfaUseBackupLink') }}\n <a (click)=\"toggleMFABackupCode()\">{{ t('mfaUseBackupAction') }}</a>\n }\n </ion-text>\n </div>\n }\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('mfaLostBackupLink') }}\n <a (click)=\"openMFAResetModal()\">{{ t('mfaResetAction') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Reset Modal (B) \u2014 recovery por email cuando no hay backup codes -->\n<ion-modal [isOpen]=\"isMFAResetModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"closeMFAResetModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"closeMFAResetModal()\">\n <strong>{{ t('close') }}</strong>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n <div class=\"logo-container\">\n <val-image [props]=\"resolvedLogo\" />\n </div>\n @if (mfaResetStep() === 'request') {\n <val-form [props]=\"mfaResetRequestFormProps()\" (onSubmit)=\"mfaResetRequestHandler($event)\" />\n } @else {\n <val-form [props]=\"mfaResetConfirmFormProps()\" (onSubmit)=\"mfaResetConfirmHandler($event)\" />\n }\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem}.oauth-buttons ion-button{--border-radius: 8px;--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"] }]
42054
42079
  }], propDecorators: { props: [{
42055
42080
  type: Input
42056
42081
  }], onSuccess: [{