@descope/web-components-ui 3.20.3 → 3.21.0
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.
- package/dist/cjs/index.cjs.js +414 -27
- package/dist/cjs/index.cjs.js.map +1 -1
- package/dist/index.esm.js +414 -27
- package/dist/index.esm.js.map +1 -1
- package/dist/umd/1411.js +339 -0
- package/dist/umd/1411.js.map +1 -0
- package/dist/umd/189.js +171 -0
- package/dist/umd/189.js.map +1 -0
- package/dist/umd/2894.js +339 -0
- package/dist/umd/2894.js.map +1 -0
- package/dist/umd/3792.js +339 -0
- package/dist/umd/3792.js.map +1 -0
- package/dist/umd/{9117.js → 384.js} +121 -9
- package/dist/umd/{descope-tooltip.js.LICENSE.txt → 384.js.LICENSE.txt} +2 -2
- package/dist/umd/384.js.map +1 -0
- package/dist/umd/4268.js +339 -0
- package/dist/umd/4268.js.LICENSE.txt +11 -0
- package/dist/umd/4268.js.map +1 -0
- package/dist/umd/513.js +339 -0
- package/dist/umd/513.js.LICENSE.txt +11 -0
- package/dist/umd/513.js.map +1 -0
- package/dist/umd/6227.js +320 -0
- package/dist/umd/6227.js.map +1 -0
- package/dist/umd/6535.js +115 -0
- package/dist/umd/{9275.js.LICENSE.txt → 6535.js.LICENSE.txt} +0 -6
- package/dist/umd/6535.js.map +1 -0
- package/dist/umd/6649.js +339 -0
- package/dist/umd/6649.js.LICENSE.txt +11 -0
- package/dist/umd/6649.js.map +1 -0
- package/dist/umd/7125.js +339 -0
- package/dist/umd/7125.js.LICENSE.txt +11 -0
- package/dist/umd/7125.js.map +1 -0
- package/dist/umd/{5263.js → 8264.js} +5 -5
- package/dist/umd/8264.js.map +1 -0
- package/dist/umd/8983.js +7 -324
- package/dist/umd/8983.js.map +1 -1
- package/dist/umd/9030.js +339 -0
- package/dist/umd/9030.js.LICENSE.txt +11 -0
- package/dist/umd/9030.js.map +1 -0
- package/dist/umd/9380.js +130 -0
- package/dist/umd/9380.js.map +1 -0
- package/dist/umd/9506.js +339 -0
- package/dist/umd/9506.js.LICENSE.txt +11 -0
- package/dist/umd/9506.js.map +1 -0
- package/dist/umd/DescopeDev.js +1 -1
- package/dist/umd/DescopeDev.js.map +1 -1
- package/dist/umd/button-selection-group-fields-descope-button-multi-selection-group-index-js.js +1 -1
- package/dist/umd/button-selection-group-fields-descope-button-multi-selection-group-index-js.js.map +1 -1
- package/dist/umd/button-selection-group-fields-descope-button-selection-group-index-js.js +1 -1
- package/dist/umd/button-selection-group-fields-descope-button-selection-group-index-js.js.map +1 -1
- package/dist/umd/button-selection-group-fields-descope-button-selection-group-item-index-js.js +1 -338
- package/dist/umd/button-selection-group-fields-descope-button-selection-group-item-index-js.js.map +1 -1
- package/dist/umd/descope-apps-list.js +161 -1
- package/dist/umd/descope-apps-list.js.LICENSE.txt +17 -0
- package/dist/umd/descope-apps-list.js.map +1 -1
- package/dist/umd/descope-avatar.js +5 -20
- package/dist/umd/descope-avatar.js.LICENSE.txt +0 -12
- package/dist/umd/descope-avatar.js.map +1 -1
- package/dist/umd/descope-button.js +3 -3
- package/dist/umd/descope-button.js.LICENSE.txt +6 -0
- package/dist/umd/descope-button.js.map +1 -1
- package/dist/umd/descope-date-field-descope-calendar-index-js.js +1 -1
- package/dist/umd/descope-date-field-descope-calendar-index-js.js.map +1 -1
- package/dist/umd/descope-email-field-index-js.js +4 -4
- package/dist/umd/descope-email-field-index-js.js.map +1 -1
- package/dist/umd/descope-grid-descope-grid-custom-column-index-js.js +4 -321
- package/dist/umd/descope-grid-descope-grid-custom-column-index-js.js.LICENSE.txt +0 -6
- package/dist/umd/descope-grid-descope-grid-custom-column-index-js.js.map +1 -1
- package/dist/umd/descope-grid-descope-grid-item-details-column-index-js.js +5 -322
- package/dist/umd/descope-grid-descope-grid-item-details-column-index-js.js.map +1 -1
- package/dist/umd/descope-grid-descope-grid-text-column-index-js.js +4 -321
- package/dist/umd/descope-grid-descope-grid-text-column-index-js.js.LICENSE.txt +0 -6
- package/dist/umd/descope-grid-descope-grid-text-column-index-js.js.map +1 -1
- package/dist/umd/descope-hybrid-field-index-js.js +2 -2
- package/dist/umd/descope-hybrid-field-index-js.js.map +1 -1
- package/dist/umd/descope-multi-line-mappings.js +1 -1
- package/dist/umd/descope-multi-line-mappings.js.map +1 -1
- package/dist/umd/descope-multi-sso.js +1 -338
- package/dist/umd/descope-multi-sso.js.map +1 -1
- package/dist/umd/descope-outbound-app-button.js +1 -338
- package/dist/umd/descope-outbound-app-button.js.map +1 -1
- package/dist/umd/descope-recovery-codes.js +1 -1
- package/dist/umd/descope-recovery-codes.js.map +1 -1
- package/dist/umd/descope-timer-button.js +1 -338
- package/dist/umd/descope-timer-button.js.map +1 -1
- package/dist/umd/descope-tooltip.js +1 -2
- package/dist/umd/descope-tooltip.js.map +1 -1
- package/dist/umd/descope-upload-file-index-js.js +1 -338
- package/dist/umd/descope-upload-file-index-js.js.map +1 -1
- package/dist/umd/descope-user-attribute-index-js.js +1 -338
- package/dist/umd/descope-user-attribute-index-js.js.map +1 -1
- package/dist/umd/descope-user-auth-method-index-js.js +1 -338
- package/dist/umd/descope-user-auth-method-index-js.js.map +1 -1
- package/dist/umd/descope-user-passkeys.js +1 -338
- package/dist/umd/descope-user-passkeys.js.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +42 -42
- package/src/components/descope-email-field/EmailFieldClass.js +50 -2
- package/src/components/descope-email-field/emailPattern.js +7 -0
- package/stories/descope-email-field.stories.js +8 -0
- package/dist/umd/1453.js +0 -177
- package/dist/umd/1453.js.LICENSE.txt +0 -29
- package/dist/umd/1453.js.map +0 -1
- package/dist/umd/5263.js.map +0 -1
- package/dist/umd/6063.js +0 -18
- package/dist/umd/6063.js.map +0 -1
- package/dist/umd/6818.js +0 -3
- package/dist/umd/6818.js.map +0 -1
- package/dist/umd/8248.js +0 -171
- package/dist/umd/8248.js.map +0 -1
- package/dist/umd/8968.js +0 -432
- package/dist/umd/8968.js.map +0 -1
- package/dist/umd/9117.js.map +0 -1
- package/dist/umd/9275.js +0 -18
- package/dist/umd/9275.js.map +0 -1
- package/dist/umd/button-selection-group-fields-descope-button-selection-group-item-index-js.js.LICENSE.txt +0 -5
- package/dist/umd/descope-multi-sso.js.LICENSE.txt +0 -5
- package/dist/umd/descope-outbound-app-button.js.LICENSE.txt +0 -5
- package/dist/umd/descope-timer-button.js.LICENSE.txt +0 -5
- package/dist/umd/descope-upload-file-index-js.js.LICENSE.txt +0 -5
- package/dist/umd/descope-user-attribute-index-js.js.LICENSE.txt +0 -5
- package/dist/umd/descope-user-passkeys.js.LICENSE.txt +0 -5
- /package/dist/umd/{8968.js.LICENSE.txt → 1411.js.LICENSE.txt} +0 -0
- /package/dist/umd/{6063.js.LICENSE.txt → 189.js.LICENSE.txt} +0 -0
- /package/dist/umd/{9117.js.LICENSE.txt → 2894.js.LICENSE.txt} +0 -0
- /package/dist/umd/{descope-user-auth-method-index-js.js.LICENSE.txt → 3792.js.LICENSE.txt} +0 -0
- /package/dist/umd/{6818.js.LICENSE.txt → 6227.js.LICENSE.txt} +0 -0
- /package/dist/umd/{5263.js.LICENSE.txt → 8264.js.LICENSE.txt} +0 -0
- /package/dist/umd/{8248.js.LICENSE.txt → 9380.js.LICENSE.txt} +0 -0
package/dist/index.esm.js
CHANGED
|
@@ -9007,25 +9007,80 @@ const DividerClass = compose(
|
|
|
9007
9007
|
|
|
9008
9008
|
customElements.define(componentName$1i, DividerClass);
|
|
9009
9009
|
|
|
9010
|
+
// Kept in its own module (with no imports) so it can be unit tested without
|
|
9011
|
+
// pulling in the whole component / vaadin dependency chain.
|
|
9012
|
+
|
|
9013
|
+
const asciiPattern = "^[\\w\\.\\%\\+\\-']+@[\\w\\.\\-]+\\.[A-Za-z]{2,}$";
|
|
9014
|
+
|
|
9015
|
+
const unicodePattern =
|
|
9016
|
+
"^[\\p{L}\\p{M}\\p{N}._%+'\\-]+@[\\p{L}\\p{M}\\p{N}.\\-]+\\.[\\p{L}\\p{M}][\\p{L}\\p{M}\\p{N}\\-]+$";
|
|
9017
|
+
|
|
9010
9018
|
const componentName$1h = getComponentName('email-field');
|
|
9011
9019
|
|
|
9012
|
-
const defaultPattern = "^[\\w\\.\\%\\+\\-']+@[\\w\\.\\-]+\\.[A-Za-z]{2,}$";
|
|
9013
9020
|
const defaultAutocomplete = 'username';
|
|
9021
|
+
const defaultInputMode = 'email';
|
|
9014
9022
|
|
|
9015
9023
|
const customMixin$e = (superclass) =>
|
|
9016
9024
|
class EmailFieldMixinClass extends superclass {
|
|
9025
|
+
// On by default - `accept-unicode="false"` restores the pre-unicode field:
|
|
9026
|
+
// native `type="email"` validation and the ASCII pattern.
|
|
9027
|
+
//
|
|
9028
|
+
// Read once, in `init`. Changing the attribute afterwards has no effect; it
|
|
9029
|
+
// is static configuration, which is how every consumer sets it.
|
|
9030
|
+
get acceptsUnicode() {
|
|
9031
|
+
return this.getAttribute('accept-unicode') !== 'false';
|
|
9032
|
+
}
|
|
9033
|
+
|
|
9017
9034
|
init() {
|
|
9018
9035
|
super.init?.();
|
|
9019
9036
|
|
|
9020
9037
|
// we need to set the pattern on the base element because vaadin-email-field is overriding it
|
|
9021
|
-
this.baseElement.setAttribute('pattern',
|
|
9038
|
+
this.baseElement.setAttribute('pattern', asciiPattern);
|
|
9022
9039
|
|
|
9023
9040
|
if (!this.getAttribute('autocomplete')) {
|
|
9024
9041
|
this.setAttribute('autocomplete', defaultAutocomplete);
|
|
9025
9042
|
}
|
|
9026
9043
|
|
|
9027
9044
|
this.createExternalInput();
|
|
9045
|
+
|
|
9046
|
+
[this.inputElement, this.externalInput].filter(Boolean).forEach((input) => {
|
|
9047
|
+
input.addEventListener('change', this.stripSurroundingWhitespace);
|
|
9048
|
+
});
|
|
9049
|
+
|
|
9050
|
+
if (this.acceptsUnicode) {
|
|
9051
|
+
this.enableUnicode();
|
|
9052
|
+
}
|
|
9028
9053
|
}
|
|
9054
|
+
|
|
9055
|
+
enableUnicode() {
|
|
9056
|
+
this.baseElement.setAttribute('pattern', unicodePattern);
|
|
9057
|
+
|
|
9058
|
+
// native `type="email"` validation is ASCII only and sets typeMismatch
|
|
9059
|
+
// before `pattern` is consulted, so `text` is what lets the pattern decide.
|
|
9060
|
+
// Through vaadin's `_setType` because `type` is a readOnly property bound
|
|
9061
|
+
// to the inner input - assigning `input.type` is re-applied over.
|
|
9062
|
+
this.baseElement._setType('text');
|
|
9063
|
+
|
|
9064
|
+
if (this.externalInput) {
|
|
9065
|
+
this.externalInput.type = 'text';
|
|
9066
|
+
}
|
|
9067
|
+
|
|
9068
|
+
// `type="text"` loses the email keyboard on mobile
|
|
9069
|
+
if (!this.getAttribute('inputmode')) {
|
|
9070
|
+
this.setAttribute('inputmode', defaultInputMode);
|
|
9071
|
+
}
|
|
9072
|
+
|
|
9073
|
+
this.externalInput?.setAttribute('inputmode', defaultInputMode);
|
|
9074
|
+
}
|
|
9075
|
+
|
|
9076
|
+
stripSurroundingWhitespace = (e) => {
|
|
9077
|
+
const trimmed = e.target.value.trim();
|
|
9078
|
+
if (trimmed === e.target.value) return;
|
|
9079
|
+
this.value = trimmed;
|
|
9080
|
+
|
|
9081
|
+
// validity is cached and was computed against the untrimmed value
|
|
9082
|
+
this.inputElement.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
|
|
9083
|
+
};
|
|
9029
9084
|
};
|
|
9030
9085
|
|
|
9031
9086
|
const EmailFieldClass = compose(
|
|
@@ -24865,6 +24920,36 @@ var collapsibleContainer$1 = /*#__PURE__*/Object.freeze({
|
|
|
24865
24920
|
|
|
24866
24921
|
const componentName$h = getComponentName$1('recovery-codes');
|
|
24867
24922
|
|
|
24923
|
+
const NO_ACTION = 'none';
|
|
24924
|
+
const DEFAULT_ERROR_MESSAGE = 'Please save your recovery codes to continue';
|
|
24925
|
+
|
|
24926
|
+
// default button label per action (buttons variant). the icons variant uses the vaadin
|
|
24927
|
+
// glyphs hardcoded in the shadow-DOM template below; the buttons variant uses image srcs.
|
|
24928
|
+
const ACTIONS = {
|
|
24929
|
+
copy: { defaultText: 'Copy' },
|
|
24930
|
+
download: { defaultText: 'Download' },
|
|
24931
|
+
};
|
|
24932
|
+
|
|
24933
|
+
// per-button config suffixes; the full attribute is `${action}-${suffix}`.
|
|
24934
|
+
// `icon`/`icon-dark` are image srcs (the seeded glyph or a custom upload), matching
|
|
24935
|
+
// the standard button's start-icon (light/dark), not a boolean.
|
|
24936
|
+
const BUTTON_SUFFIXES = [
|
|
24937
|
+
'text',
|
|
24938
|
+
'variant',
|
|
24939
|
+
'color',
|
|
24940
|
+
'size',
|
|
24941
|
+
'icon',
|
|
24942
|
+
'icon-dark',
|
|
24943
|
+
];
|
|
24944
|
+
|
|
24945
|
+
// changing any of these rebuilds the buttons (so the editor preview stays live)
|
|
24946
|
+
const BUTTON_ATTRS = [
|
|
24947
|
+
'show-download',
|
|
24948
|
+
...Object.keys(ACTIONS).flatMap((action) =>
|
|
24949
|
+
BUTTON_SUFFIXES.map((suffix) => `${action}-${suffix}`),
|
|
24950
|
+
),
|
|
24951
|
+
];
|
|
24952
|
+
|
|
24868
24953
|
const itemRenderer$4 = ({ value }, _, ref) => {
|
|
24869
24954
|
return `
|
|
24870
24955
|
<descope-text variant="${ref.variant}" mode="${ref.mode}">
|
|
@@ -24878,24 +24963,44 @@ class RawRecoveryCodes extends createBaseClass$1({
|
|
|
24878
24963
|
baseSelector: ':host > div',
|
|
24879
24964
|
}) {
|
|
24880
24965
|
static get observedAttributes() {
|
|
24881
|
-
return ['readonly'];
|
|
24966
|
+
return ['readonly', 'required', ...BUTTON_ATTRS];
|
|
24882
24967
|
}
|
|
24883
24968
|
|
|
24969
|
+
// 'none' | 'copied' | 'downloaded' - the last action the user took on the codes
|
|
24970
|
+
#action = NO_ACTION;
|
|
24971
|
+
|
|
24972
|
+
// the error is shown only after a submit attempt (reportValidity), like inputs
|
|
24973
|
+
#showError = false;
|
|
24974
|
+
|
|
24975
|
+
// init() builds the buttons once with all seeded attrs; guards against rebuilding
|
|
24976
|
+
// on every per-attribute change fired during element upgrade (before init runs)
|
|
24977
|
+
#initialized = false;
|
|
24978
|
+
|
|
24884
24979
|
constructor() {
|
|
24885
24980
|
super();
|
|
24886
24981
|
|
|
24887
24982
|
this.attachShadow({ mode: 'open' }).innerHTML = `
|
|
24888
24983
|
<div class="wrapper">
|
|
24889
|
-
<div class="
|
|
24890
|
-
|
|
24891
|
-
<
|
|
24892
|
-
|
|
24984
|
+
<div class="codes-box">
|
|
24985
|
+
<div class="list"></div>
|
|
24986
|
+
<descope-text class="icon-wrapper">
|
|
24987
|
+
<div class="icons">
|
|
24988
|
+
<vaadin-icon class="icon copy-icon" icon="vaadin:copy-o" title="Copy"></vaadin-icon>
|
|
24989
|
+
<vaadin-icon class="icon download-icon" icon="vaadin:download-alt" title="Download"></vaadin-icon>
|
|
24990
|
+
</div>
|
|
24991
|
+
</descope-text>
|
|
24992
|
+
</div>
|
|
24993
|
+
<div class="error-message"></div>
|
|
24994
|
+
<div class="buttons-row"></div>
|
|
24893
24995
|
</div>
|
|
24894
24996
|
`;
|
|
24895
24997
|
|
|
24896
24998
|
this.list = this.shadowRoot.querySelector('.list');
|
|
24897
|
-
this.
|
|
24999
|
+
this.copyIcon = this.shadowRoot.querySelector('.copy-icon');
|
|
25000
|
+
this.downloadIcon = this.shadowRoot.querySelector('.download-icon');
|
|
24898
25001
|
this.iconWrapper = this.shadowRoot.querySelector('.icon-wrapper');
|
|
25002
|
+
this.errorMessageEle = this.shadowRoot.querySelector('.error-message');
|
|
25003
|
+
this.buttonsRow = this.shadowRoot.querySelector('.buttons-row');
|
|
24899
25004
|
|
|
24900
25005
|
injectStyle(
|
|
24901
25006
|
`
|
|
@@ -24904,8 +25009,14 @@ class RawRecoveryCodes extends createBaseClass$1({
|
|
|
24904
25009
|
position: relative;
|
|
24905
25010
|
}
|
|
24906
25011
|
.wrapper {
|
|
25012
|
+
display: flex;
|
|
25013
|
+
flex-direction: column;
|
|
25014
|
+
}
|
|
25015
|
+
.codes-box {
|
|
24907
25016
|
display: flex;
|
|
24908
25017
|
justify-content: space-between;
|
|
25018
|
+
box-sizing: border-box;
|
|
25019
|
+
/* border shows the error ring inside the box; style/width/color/radius come from theme */
|
|
24909
25020
|
}
|
|
24910
25021
|
.list {
|
|
24911
25022
|
display: flex;
|
|
@@ -24924,15 +25035,57 @@ class RawRecoveryCodes extends createBaseClass$1({
|
|
|
24924
25035
|
.icon-wrapper {
|
|
24925
25036
|
align-self: flex-start;
|
|
24926
25037
|
}
|
|
25038
|
+
.icons {
|
|
25039
|
+
display: flex;
|
|
25040
|
+
flex-direction: column;
|
|
25041
|
+
}
|
|
24927
25042
|
.icon {
|
|
24928
25043
|
cursor: pointer;
|
|
24929
25044
|
}
|
|
24930
25045
|
.icon.copied {
|
|
24931
25046
|
cursor: initial;
|
|
25047
|
+
/* block re-clicks while the checkmark shows, so rapid clicks cannot repeat the action */
|
|
25048
|
+
pointer-events: none;
|
|
24932
25049
|
}
|
|
24933
|
-
|
|
25050
|
+
/* readonly is a host attribute, so disable pointer events from one place */
|
|
25051
|
+
:host([readonly="true"]) .icon,
|
|
25052
|
+
:host([readonly="true"]) .buttons-row {
|
|
24934
25053
|
pointer-events: none;
|
|
24935
25054
|
}
|
|
25055
|
+
.download-icon {
|
|
25056
|
+
display: none;
|
|
25057
|
+
}
|
|
25058
|
+
:host([show-download="true"]) .download-icon {
|
|
25059
|
+
display: inline-flex;
|
|
25060
|
+
}
|
|
25061
|
+
.error-message {
|
|
25062
|
+
display: none;
|
|
25063
|
+
/* width:0 + min-width:100% lets the message wrap to the component width without
|
|
25064
|
+
its text expanding the (shrink-to-fit) component; full-width still fills the parent */
|
|
25065
|
+
width: 0;
|
|
25066
|
+
min-width: 100%;
|
|
25067
|
+
box-sizing: border-box;
|
|
25068
|
+
line-height: 1.2;
|
|
25069
|
+
overflow-wrap: break-word;
|
|
25070
|
+
}
|
|
25071
|
+
:host([invalid]) .error-message {
|
|
25072
|
+
display: block;
|
|
25073
|
+
}
|
|
25074
|
+
.buttons-row {
|
|
25075
|
+
display: none;
|
|
25076
|
+
}
|
|
25077
|
+
:host([display-variant="buttons"]) .icon-wrapper {
|
|
25078
|
+
display: none;
|
|
25079
|
+
}
|
|
25080
|
+
:host([display-variant="buttons"]) .buttons-row {
|
|
25081
|
+
display: flex;
|
|
25082
|
+
flex-wrap: wrap;
|
|
25083
|
+
}
|
|
25084
|
+
/* grow to fill equally; don't shrink below content, so they wrap to a new line
|
|
25085
|
+
when they don't fit (like a container with auto-fit items) */
|
|
25086
|
+
.buttons-row > descope-button {
|
|
25087
|
+
flex: 1 0 auto;
|
|
25088
|
+
}
|
|
24936
25089
|
`,
|
|
24937
25090
|
this,
|
|
24938
25091
|
);
|
|
@@ -24946,41 +25099,190 @@ class RawRecoveryCodes extends createBaseClass$1({
|
|
|
24946
25099
|
return this.getAttribute('mode');
|
|
24947
25100
|
}
|
|
24948
25101
|
|
|
25102
|
+
// the form value read by the flow SDK (#getFormData reads `.value`)
|
|
25103
|
+
get value() {
|
|
25104
|
+
return this.#action;
|
|
25105
|
+
}
|
|
25106
|
+
|
|
25107
|
+
// a boolean attribute is "on" when present and not explicitly "false"
|
|
25108
|
+
#boolAttr(name) {
|
|
25109
|
+
return this.hasAttribute(name) && this.getAttribute(name) !== 'false';
|
|
25110
|
+
}
|
|
25111
|
+
|
|
25112
|
+
get isRequired() {
|
|
25113
|
+
return this.#boolAttr('required');
|
|
25114
|
+
}
|
|
25115
|
+
|
|
25116
|
+
get isReadOnly() {
|
|
25117
|
+
return this.#boolAttr('readonly');
|
|
25118
|
+
}
|
|
25119
|
+
|
|
25120
|
+
get errorMessage() {
|
|
25121
|
+
return (
|
|
25122
|
+
this.getAttribute('data-errormessage-value-missing') ||
|
|
25123
|
+
DEFAULT_ERROR_MESSAGE
|
|
25124
|
+
);
|
|
25125
|
+
}
|
|
25126
|
+
|
|
25127
|
+
get codesText() {
|
|
25128
|
+
return String((this.data || []).map((rc) => rc.value).join('\n'));
|
|
25129
|
+
}
|
|
25130
|
+
|
|
24949
25131
|
init() {
|
|
24950
25132
|
super.init();
|
|
24951
25133
|
|
|
24952
|
-
this.
|
|
25134
|
+
this.copyIcon.addEventListener('click', this.onCopy.bind(this));
|
|
25135
|
+
this.downloadIcon.addEventListener('click', this.onDownload.bind(this));
|
|
24953
25136
|
|
|
24954
25137
|
forwardAttrs$1(this, this.iconWrapper, { includeAttrs: ['variant', 'mode'] });
|
|
25138
|
+
|
|
25139
|
+
this.renderButtons();
|
|
25140
|
+
this.#initialized = true;
|
|
24955
25141
|
}
|
|
24956
25142
|
|
|
24957
|
-
|
|
24958
|
-
|
|
24959
|
-
|
|
25143
|
+
get isDownloadEnabled() {
|
|
25144
|
+
return this.getAttribute('show-download') === 'true';
|
|
25145
|
+
}
|
|
25146
|
+
|
|
25147
|
+
// buttons variant: copy (+ download when enabled) as descope-buttons, each independently
|
|
25148
|
+
// configurable. rendered even in the icons variant (CSS hides the row) so a variant switch is instant.
|
|
25149
|
+
renderButtons() {
|
|
25150
|
+
if (!this.buttonsRow) return;
|
|
25151
|
+
|
|
25152
|
+
const buttons = [this.buildButton('copy')];
|
|
25153
|
+
if (this.isDownloadEnabled) {
|
|
25154
|
+
buttons.push(this.buildButton('download'));
|
|
25155
|
+
}
|
|
25156
|
+
this.buttonsRow.replaceChildren(...buttons);
|
|
25157
|
+
}
|
|
25158
|
+
|
|
25159
|
+
buildButton(action) {
|
|
25160
|
+
const { defaultText } = ACTIONS[action];
|
|
25161
|
+
const attr = (name, fallback) =>
|
|
25162
|
+
this.getAttribute(`${action}-${name}`) || fallback;
|
|
25163
|
+
|
|
25164
|
+
const button = document.createElement('descope-button');
|
|
25165
|
+
button.setAttribute('data-action', action);
|
|
25166
|
+
button.setAttribute('variant', attr('variant', 'outline'));
|
|
25167
|
+
button.setAttribute('mode', attr('color', 'primary'));
|
|
25168
|
+
button.setAttribute('size', attr('size', 'md'));
|
|
25169
|
+
|
|
25170
|
+
// icon is an image src - the seeded glyph or a custom upload (light/dark),
|
|
25171
|
+
// same as the standard button's start icon. rendered via descope-icon in the
|
|
25172
|
+
// default slot (not slot="prefix") so it centers with the label when the
|
|
25173
|
+
// button grows. descope-icon inlines SVGs, so the glyph (authored with
|
|
25174
|
+
// fill="currentColor") tracks the button text color while an uploaded image
|
|
25175
|
+
// keeps its own colors.
|
|
25176
|
+
const iconSrc = this.getAttribute(`${action}-icon`);
|
|
25177
|
+
if (iconSrc) {
|
|
25178
|
+
const icon = document.createElement('descope-icon');
|
|
25179
|
+
icon.setAttribute('src', iconSrc);
|
|
25180
|
+
const iconDark = this.getAttribute(`${action}-icon-dark`);
|
|
25181
|
+
if (iconDark) icon.setAttribute('src-dark', iconDark);
|
|
25182
|
+
button.appendChild(icon);
|
|
25183
|
+
}
|
|
25184
|
+
|
|
25185
|
+
button.appendChild(document.createTextNode(attr('text', defaultText)));
|
|
25186
|
+
button.addEventListener('click', () =>
|
|
25187
|
+
action === 'copy' ? this.onCopy() : this.onDownload(),
|
|
24960
25188
|
);
|
|
25189
|
+
return button;
|
|
25190
|
+
}
|
|
24961
25191
|
|
|
24962
|
-
|
|
24963
|
-
this.
|
|
24964
|
-
|
|
25192
|
+
onCopy() {
|
|
25193
|
+
if (this.isReadOnly) return;
|
|
25194
|
+
navigator.clipboard.writeText(this.codesText);
|
|
25195
|
+
this.showActionFeedback(this.copyIcon, 'Copied');
|
|
25196
|
+
this.recordAction('copied');
|
|
25197
|
+
}
|
|
24965
25198
|
|
|
24966
|
-
|
|
24967
|
-
|
|
24968
|
-
|
|
24969
|
-
|
|
25199
|
+
onDownload() {
|
|
25200
|
+
if (this.isReadOnly) return;
|
|
25201
|
+
const blob = new Blob([this.codesText], { type: 'text/plain' });
|
|
25202
|
+
const url = URL.createObjectURL(blob);
|
|
25203
|
+
const anchor = document.createElement('a');
|
|
25204
|
+
anchor.href = url;
|
|
25205
|
+
anchor.download = 'recovery-codes.txt';
|
|
25206
|
+
anchor.click();
|
|
25207
|
+
URL.revokeObjectURL(url);
|
|
25208
|
+
|
|
25209
|
+
this.showActionFeedback(this.downloadIcon, 'Downloaded');
|
|
25210
|
+
this.recordAction('downloaded');
|
|
25211
|
+
}
|
|
25212
|
+
|
|
25213
|
+
// copy/download share this - only the visual feedback differs by variant
|
|
25214
|
+
recordAction(action) {
|
|
25215
|
+
this.#action = action;
|
|
25216
|
+
// let the flow re-evaluate real-time conditions and pick up the new value
|
|
25217
|
+
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
25218
|
+
// acting clears the mandatory error
|
|
25219
|
+
if (this.checkValidity()) {
|
|
25220
|
+
this.#showError = false;
|
|
25221
|
+
}
|
|
25222
|
+
this.syncValidityUI();
|
|
25223
|
+
}
|
|
25224
|
+
|
|
25225
|
+
// icons variant: swap the icon to a checkmark for 5s (buttons variant is static)
|
|
25226
|
+
showActionFeedback(iconEle, doneTitle) {
|
|
25227
|
+
// on a rapid re-click the checkmark is already showing, so cancel the pending restore
|
|
25228
|
+
// and keep the glyph/title we saved the first time (never capture the checkmark itself)
|
|
25229
|
+
if (iconEle.feedbackTimer) {
|
|
25230
|
+
clearTimeout(iconEle.feedbackTimer);
|
|
25231
|
+
} else {
|
|
25232
|
+
iconEle.originalIcon = iconEle.getAttribute('icon');
|
|
25233
|
+
iconEle.originalTitle = iconEle.getAttribute('title');
|
|
25234
|
+
}
|
|
25235
|
+
|
|
25236
|
+
iconEle.setAttribute('icon', 'vaadin:check-circle-o');
|
|
25237
|
+
iconEle.setAttribute('title', doneTitle);
|
|
25238
|
+
iconEle.classList.add('copied');
|
|
25239
|
+
|
|
25240
|
+
iconEle.feedbackTimer = setTimeout(() => {
|
|
25241
|
+
iconEle.setAttribute('icon', iconEle.originalIcon);
|
|
25242
|
+
iconEle.setAttribute('title', iconEle.originalTitle);
|
|
25243
|
+
iconEle.classList.remove('copied');
|
|
25244
|
+
iconEle.feedbackTimer = null;
|
|
24970
25245
|
}, 5000);
|
|
24971
25246
|
}
|
|
24972
25247
|
|
|
24973
|
-
|
|
24974
|
-
|
|
25248
|
+
// the flow SDK's #validateInputs calls checkValidity/reportValidity on every *[name]
|
|
25249
|
+
checkValidity() {
|
|
25250
|
+
return this.isReadOnly || !this.isRequired || this.value !== NO_ACTION;
|
|
25251
|
+
}
|
|
25252
|
+
|
|
25253
|
+
reportValidity() {
|
|
25254
|
+
const valid = this.checkValidity();
|
|
25255
|
+
this.#showError = !valid;
|
|
25256
|
+
this.syncValidityUI();
|
|
25257
|
+
return valid;
|
|
25258
|
+
}
|
|
25259
|
+
|
|
25260
|
+
// single source of truth for the error UI - reflects `invalid` (theme `_invalid`
|
|
25261
|
+
// draws the outline) and fills the message. never toggled anywhere else.
|
|
25262
|
+
syncValidityUI() {
|
|
25263
|
+
this.toggleAttribute('invalid', this.#showError);
|
|
25264
|
+
if (this.errorMessageEle) {
|
|
25265
|
+
this.errorMessageEle.textContent = this.#showError
|
|
25266
|
+
? this.errorMessage
|
|
25267
|
+
: '';
|
|
25268
|
+
}
|
|
24975
25269
|
}
|
|
24976
25270
|
|
|
24977
25271
|
attributeChangedCallback(attrName, oldValue, newValue) {
|
|
24978
25272
|
super.attributeChangedCallback?.(attrName, oldValue, newValue);
|
|
24979
25273
|
|
|
24980
|
-
if (newValue
|
|
24981
|
-
|
|
24982
|
-
|
|
24983
|
-
|
|
25274
|
+
if (newValue === oldValue) return;
|
|
25275
|
+
|
|
25276
|
+
// if it stops being required, drop any error already shown
|
|
25277
|
+
if (attrName === 'required' && !this.isRequired) {
|
|
25278
|
+
this.#showError = false;
|
|
25279
|
+
this.syncValidityUI();
|
|
25280
|
+
}
|
|
25281
|
+
|
|
25282
|
+
// only rebuild for live edits after init (init already built once with all attrs);
|
|
25283
|
+
// avoids rebuilding once per attribute during the initial element upgrade
|
|
25284
|
+
if (this.#initialized && BUTTON_ATTRS.includes(attrName)) {
|
|
25285
|
+
this.renderButtons();
|
|
24984
25286
|
}
|
|
24985
25287
|
}
|
|
24986
25288
|
}
|
|
@@ -25000,10 +25302,66 @@ const RecoveryCodesClass = compose$1(
|
|
|
25000
25302
|
textAlign: { selector: () => '.list', property: 'align-items' },
|
|
25001
25303
|
iconColor: { selector: () => 'vaadin-icon', property: 'color' },
|
|
25002
25304
|
iconSize: { selector: () => 'vaadin-icon', property: 'font-size' },
|
|
25003
|
-
iconGap: { selector: () => '.
|
|
25305
|
+
iconGap: { selector: () => '.codes-box', property: 'gap' },
|
|
25306
|
+
iconStackGap: { selector: () => '.icons', property: 'gap' },
|
|
25307
|
+
buttonsGap: { selector: () => '.buttons-row', property: 'gap' },
|
|
25308
|
+
sectionsGap: { selector: () => '.wrapper', property: 'gap' },
|
|
25004
25309
|
bulletGap: { selector: () => 'descope-text span', property: 'gap' },
|
|
25310
|
+
// top + bottom padding sit inside the border (below the codes) in both variants; in the
|
|
25311
|
+
// buttons variant the bottom padding also repeats below the buttons (the buttons-row entry
|
|
25312
|
+
// is inert in the icons variant, where the row is display:none).
|
|
25313
|
+
verticalPadding: [
|
|
25314
|
+
{ selector: () => '.codes-box', property: 'padding-top' },
|
|
25315
|
+
{ selector: () => '.codes-box', property: 'padding-bottom' },
|
|
25316
|
+
{ selector: () => '.buttons-row', property: 'padding-bottom' },
|
|
25317
|
+
],
|
|
25318
|
+
// horizontal padding insets the codes (inside the border) and the buttons, but NOT the
|
|
25319
|
+
// error message, which stays aligned to the component edge (like the input error).
|
|
25320
|
+
horizontalPadding: [
|
|
25321
|
+
{ selector: () => '.codes-box', property: 'padding-left' },
|
|
25322
|
+
{ selector: () => '.codes-box', property: 'padding-right' },
|
|
25323
|
+
{ selector: () => '.buttons-row', property: 'padding-left' },
|
|
25324
|
+
{ selector: () => '.buttons-row', property: 'padding-right' },
|
|
25325
|
+
],
|
|
25326
|
+
errorBorderColor: {
|
|
25327
|
+
selector: () => '.codes-box',
|
|
25328
|
+
property: 'border-color',
|
|
25329
|
+
},
|
|
25330
|
+
errorMessageColor: {
|
|
25331
|
+
selector: () => '.error-message',
|
|
25332
|
+
property: 'color',
|
|
25333
|
+
},
|
|
25334
|
+
errorMessageFontSize: {
|
|
25335
|
+
selector: () => '.error-message',
|
|
25336
|
+
property: 'font-size',
|
|
25337
|
+
},
|
|
25338
|
+
errorMessageFontWeight: {
|
|
25339
|
+
selector: () => '.error-message',
|
|
25340
|
+
property: 'font-weight',
|
|
25341
|
+
},
|
|
25342
|
+
errorMessageFontFamily: {
|
|
25343
|
+
selector: () => '.error-message',
|
|
25344
|
+
property: 'font-family',
|
|
25345
|
+
},
|
|
25346
|
+
boxBorderRadius: {
|
|
25347
|
+
selector: () => '.codes-box',
|
|
25348
|
+
property: 'border-radius',
|
|
25349
|
+
},
|
|
25350
|
+
errorBorderWidth: {
|
|
25351
|
+
selector: () => '.codes-box',
|
|
25352
|
+
property: 'border-width',
|
|
25353
|
+
},
|
|
25354
|
+
boxBorderStyle: {
|
|
25355
|
+
selector: () => '.codes-box',
|
|
25356
|
+
property: 'border-style',
|
|
25357
|
+
},
|
|
25005
25358
|
},
|
|
25006
25359
|
}),
|
|
25360
|
+
// also inject the shared input-wrapper theme onto our host (like the input components do),
|
|
25361
|
+
// so the error message + border track the console "customize inputs" tokens
|
|
25362
|
+
createStyleMixin$1({
|
|
25363
|
+
componentNameOverride: getComponentName$1('input-wrapper'),
|
|
25364
|
+
}),
|
|
25007
25365
|
createDynamicDataMixin$1({
|
|
25008
25366
|
itemRenderer: itemRenderer$4,
|
|
25009
25367
|
rerenderAttrsList: ['variant', 'mode'],
|
|
@@ -25022,9 +25380,33 @@ const recoveryCodes = {
|
|
|
25022
25380
|
[vars$T.hostDirection]: globalRefs$t.direction,
|
|
25023
25381
|
[vars$T.iconColor]: useVar$1(textVars$1.textColor),
|
|
25024
25382
|
[vars$T.iconSize]: useVar$1(textVars$1.fontSize),
|
|
25383
|
+
// gap between the codes and the icon column
|
|
25025
25384
|
[vars$T.iconGap]: '8px',
|
|
25385
|
+
// gap between the stacked copy and download icons
|
|
25386
|
+
[vars$T.iconStackGap]: '16px',
|
|
25387
|
+
// gap between the copy and download buttons (buttons variant)
|
|
25388
|
+
[vars$T.buttonsGap]: '8px',
|
|
25389
|
+
// gap between the codes, the error message and the buttons
|
|
25390
|
+
[vars$T.sectionsGap]: '8px',
|
|
25026
25391
|
[vars$T.bulletGap]: '0.35em',
|
|
25027
25392
|
|
|
25393
|
+
// no padding by default so the current look is unchanged; the editor overrides per instance
|
|
25394
|
+
[vars$T.verticalPadding]: '0',
|
|
25395
|
+
[vars$T.horizontalPadding]: '0',
|
|
25396
|
+
|
|
25397
|
+
// error ring is transparent until the component is marked invalid (see _invalid below).
|
|
25398
|
+
// message color/font + border come from the shared input-wrapper tokens, so customizing
|
|
25399
|
+
// inputs in the console updates the recovery-codes error styling from the same place.
|
|
25400
|
+
[vars$T.errorBorderColor]: 'transparent',
|
|
25401
|
+
[vars$T.errorBorderWidth]: refs$1.borderWidth,
|
|
25402
|
+
[vars$T.boxBorderRadius]: refs$1.borderRadius,
|
|
25403
|
+
// local default; can later map to the input-wrapper border style if it exposes one
|
|
25404
|
+
[vars$T.boxBorderStyle]: 'solid',
|
|
25405
|
+
[vars$T.errorMessageColor]: refs$1.errorMessageTextColor,
|
|
25406
|
+
[vars$T.errorMessageFontSize]: refs$1.errorMessageFontSize,
|
|
25407
|
+
[vars$T.errorMessageFontWeight]: refs$1.errorMessageFontWeight,
|
|
25408
|
+
[vars$T.errorMessageFontFamily]: refs$1.fontFamily,
|
|
25409
|
+
|
|
25028
25410
|
textAlign: {
|
|
25029
25411
|
right: { [vars$T.textAlign]: 'flex-end' },
|
|
25030
25412
|
left: { [vars$T.textAlign]: 'flex-start' },
|
|
@@ -25034,6 +25416,11 @@ const recoveryCodes = {
|
|
|
25034
25416
|
_fullWidth: {
|
|
25035
25417
|
[vars$T.hostWidth]: '100%',
|
|
25036
25418
|
},
|
|
25419
|
+
|
|
25420
|
+
// reflected `invalid` attribute (set by the component on a failed submit)
|
|
25421
|
+
_invalid: {
|
|
25422
|
+
[vars$T.errorBorderColor]: refs$1.errorMessageTextColor,
|
|
25423
|
+
},
|
|
25037
25424
|
};
|
|
25038
25425
|
|
|
25039
25426
|
var recoveryCodes$1 = /*#__PURE__*/Object.freeze({
|