@internetarchive/elements 0.2.10 → 0.2.12-rc.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/README.md CHANGED
@@ -87,9 +87,15 @@ Add to Jest config:
87
87
 
88
88
  ## Development
89
89
 
90
+ Requires Node 24+ and pnpm 11+. `engine-strict=true` in `.npmrc` makes an older
91
+ Node fail the install instead of warning, but nothing hard-blocks `npm install`:
92
+ npm ignores `engines.pnpm`, and there's deliberately no preinstall guard since it
93
+ would run for consumers too. Use pnpm. `packageManager` and the committed
94
+ `pnpm-lock.yaml` are what point you at it.
95
+
90
96
  ```zsh
91
- npm i
92
- npm run dev
97
+ pnpm install
98
+ pnpm run dev
93
99
  ```
94
100
 
95
101
  ## Versioning and Publishing
@@ -97,10 +103,10 @@ npm run dev
97
103
  ### Prerelease Version
98
104
 
99
105
  1. Create prerelease version on your branch:
100
- 1. `npm version prerelease --preid=<some_prefix>`
106
+ 1. `pnpm version prerelease --preid=<some_prefix>`
101
107
  2. If you use JIRA, recommend using the ticket number, ie `--preid=webdev-1234`
102
108
  3. This will also create a `git` tag
103
- 2. Push the tag that was created in the `npm version` step
109
+ 2. Push the tag that was created in the `pnpm version` step
104
110
  3. Publish prerelease to npm:
105
111
  1. Go to the [Element release page](https://github.com/internetarchive/elements/releases)
106
112
  2. Tap `Draft a new release` button
@@ -113,7 +119,7 @@ npm run dev
113
119
 
114
120
  1. Use [Semantic Versioning](https://semver.org) to determine release number
115
121
  2. On the `main` branch:
116
- 1. Run `npm version [major | minor | patch]`
122
+ 1. Run `pnpm version [major | minor | patch]`
117
123
  2. `git push && git push --tags`
118
124
  3. Publish release to npm:
119
125
  1. Go to the [Element release page](https://github.com/internetarchive/elements/releases)
@@ -300,7 +300,7 @@ let IAButton = class IAButton extends LitElement {
300
300
  border-color: var(--ia-button-custom-border--);
301
301
  }
302
302
 
303
- button.custom:enabled:is(:hover, :focus, :active) {
303
+ button.custom:enabled:is(:hover, :focus, :active, .active) {
304
304
  color: var(--ia-button-custom-active-text-color--);
305
305
  background-color: var(--ia-button-custom-active-fill--);
306
306
  border-color: var(--ia-button-custom-active-border--);
@@ -1 +1 @@
1
- {"version":3,"file":"ia-button.js","sourceRoot":"","sources":["../../../../src/elements/ia-button/ia-button.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n html,\n LitElement,\n TemplateResult,\n CSSResultGroup,\n css,\n PropertyValues,\n render,\n} from 'lit';\nimport { msg } from '@lit/localize';\nimport { property, customElement } from 'lit/decorators.js';\nimport themeStyles from '@src/themes/theme-styles';\n\nimport '../ia-status-indicator/ia-status-indicator';\n\n/**\n * Renders a standardized button built off the ia-button styling and the activity indicator, with the option to show\n * a loading indicator instead of the text or to customize the text, and the ability to pass in any\n * function to run on click.\n *\n * Designed to behave exactly like a native type=\"submit\" or type=\"reset\" button if either type is supplied,\n * i.e. for an <ia-button type=\"submit\" @click=${doSideEffects}></ia-button>,\n * whether the form is submitted via enter or by clicking the button directly, the button will always\n * run doSideEffects() and then submit the form.\n */\n@customElement('ia-button')\nexport class IAButton extends LitElement {\n /* Which version of the button to display */\n @property({ type: String }) mode:\n | 'primary'\n | 'secondary'\n | 'danger'\n | 'warning'\n | 'disabled'\n | 'transparent'\n | 'custom'\n | 'link'\n | 'danger-link' = 'primary';\n\n /* Whether to show a loading indicator instead of the button */\n @property({ type: Boolean }) loading: boolean = false;\n\n /* Whether the button should be disabled, regardless of submission status */\n @property({ type: Boolean }) disabled: boolean = false;\n\n /* Optional text to include next to the loading indicator */\n @property({ type: String }) loadingText: string = '';\n\n /* Type of the button - defaults to 'button' to prevent form submission */\n @property({ type: String, reflect: true }) type:\n | 'button'\n | 'submit'\n | 'reset' = 'button';\n\n /* An optional href to wrap around the button */\n @property({ type: String }) href?: string;\n\n /* Whether to add a target=\"_blank\" to any wrapping link */\n @property({ type: Boolean }) openLinksNewTab: boolean = false;\n\n render(): TemplateResult {\n return html`\n ${this.href\n ? html`<a\n href=${this.href}\n target=${this.openLinksNewTab ? '_blank' : '_self'}\n >${this.buttonTemplate}</a\n >`\n : this.buttonTemplate}\n <slot name=\"hidden-button\"></slot>\n `;\n }\n\n protected willUpdate(changed: PropertyValues): void {\n if (changed.has('type')) {\n this.setButtonTypeEmulation();\n }\n }\n\n /* The native button to render */\n private get buttonTemplate(): TemplateResult {\n return html`\n <button\n part=\"button\"\n class=${this.mode}\n ?disabled=${this.disabled || this.loading}\n >\n ${this.buttonTextTemplate}\n </button>\n `;\n }\n\n /* The text to render within the button */\n private get buttonTextTemplate(): TemplateResult {\n return this.loading ? this.loadingStateTemplate : html`<slot></slot>`;\n }\n\n /* Content to render while button is loading */\n private get loadingStateTemplate(): TemplateResult {\n return html`\n <span class=\"loading-indicator\" alt=\"Loading indicator\">\n <ia-status-indicator mode=\"loading\"></ia-status-indicator> ${msg(\n this.loadingText,\n )}\n </span>\n `;\n }\n\n /** Sets up or removes button type emulation as needed */\n private setButtonTypeEmulation(): void {\n const hiddenButton: HTMLInputElement | null = this.querySelector(\n 'input.hidden-button',\n );\n\n if (hiddenButton) {\n hiddenButton.type = this.type;\n return;\n }\n\n this.addHiddenButton();\n this.addEventListener('click', this.handleComponentClick);\n }\n\n /**\n * Triggers form actions (submit/reset) on click, if desired\n * and if actions not already in progress\n */\n private handleComponentClick(e: Event): void {\n if (this.type === 'button') return;\n\n // No need to submit/reset the form if it's already submitting/resetting\n const formActionsInProgress =\n e instanceof CustomEvent && e.detail.formActionsInProgress;\n if (formActionsInProgress) return;\n\n // Request form submission/reset by clicking the hidden native submit/reset button we added earlier\n const hiddenButton = this.querySelector(\n 'input.hidden-button',\n ) as HTMLInputElement;\n hiddenButton.dispatchEvent(new PointerEvent('click'));\n }\n\n /**\n * Adds a hidden button to the light DOM to\n * emulate native reset/submit button behavior.\n *\n * Used for:\n * - Submitting/resetting the form (on behalf of handleComponentClick)\n * - Activating any component click events if form is submitted with the enter key\n * (via handleFormActions)\n */\n private addHiddenButton(): void {\n if (this.type === 'button') return;\n\n render(\n html`<input\n type=${this.type}\n class=\"hidden-button\"\n style=\"display:none\"\n slot=\"hidden-button\"\n @click=${(e: Event) => this.handleFormActions(e)}\n />`,\n this,\n );\n }\n\n /** Triggers the component's click event manually to prevent extra submission/reset */\n private handleFormActions(e: Event): void {\n /**\n * Prevents the event from bubbling up to the ia-button component itself.\n * This way, if the click on this button is triggered by a click on the component,\n * we don't accidentally bubble up a second click and end up in an infinite loop.\n *\n * And if the click was triggered by form submission (via the enter key), we can hijack the click\n * event to pass that info to the component, so it knows not to\n * re-attempt submission.\n */\n e.stopPropagation();\n\n // Detect if click comes from the parent component,\n // in which case there's no need to trigger a second click on it\n const triggeredByComponentClick = !e.isTrusted;\n if (triggeredByComponentClick) return;\n\n // Trigger parent component click events manually,\n // so it knows not to try to re-submit/re-reset the form\n this.dispatchEvent(\n new CustomEvent('click', { detail: { formActionsInProgress: true } }),\n );\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --primary-cta-text-color--: var(--primary-cta-text-color);\n --primary-cta-fill--: var(--primary-cta-fill);\n --primary-cta-border--: var(--primary-cta-border);\n\n --secondary-cta-text-color--: var(--secondary-cta-text-color);\n --secondary-cta-fill--: var(--secondary-cta-fill);\n --secondary-cta-border--: var(--secondary-cta-border);\n\n --danger-cta-text-color--: var(--danger-cta-text-color);\n --danger-cta-fill--: var(--danger-cta-fill);\n --danger-cta-border--: var(--danger-cta-border);\n\n --warning-cta-text-color--: var(--warning-cta-text-color);\n --warning-cta-fill--: var(--warning-cta-fill);\n --warning-cta-border--: var(--warning-cta-border);\n\n --disabled-cta-text-color--: var(--disabled-cta-text-color);\n --disabled-cta-fill--: var(--disabled-cta-fill);\n --disabled-cta-border--: var(--disabled-cta-border);\n\n --link-color--: var(--link-color);\n --color-danger--: var(--color-danger);\n\n --button-padding--: var(--button-padding);\n --button-width--: var(--button-width);\n --button-height--: var(--button-height);\n --button-border-width--: var(--button-border-width);\n --button-border-radius--: var(--button-border-radius);\n --base-font-family--: var(--base-font-family);\n --font-size-standard--: var(--font-size-standard);\n\n --ia-button-transition--: var(\n --ia-button-transition,\n all 0.1s ease 0s\n );\n\n --ia-button-custom-text-color--: var(\n --ia-button-custom-text-color,\n var(--primary-cta-text-color--)\n );\n --ia-button-custom-fill--: var(\n --ia-button-custom-fill,\n var(--primary-cta-fill--)\n );\n --ia-button-custom-border--: var(\n --ia-button-custom-border,\n var(--primary-cta-border--)\n );\n --ia-button-custom-active-text-color--: var(\n --ia-button-custom-active-text-color,\n var(--ia-button-custom-text-color--)\n );\n --ia-button-custom-active-fill--: var(\n --ia-button-custom-active-fill,\n var(--ia-button-custom-fill--)\n );\n --ia-button-custom-active-border--: var(\n --ia-button-custom-active-border,\n var(--ia-button-custom-border--)\n );\n\n display: inline-block; /* keeps host sized to button */\n }\n\n button {\n font-family: var(--base-font-family--);\n font-size: var(--font-size-standard--);\n height: var(--button-height--);\n min-height: var(--button-height--);\n width: var(--button-width--);\n padding: var(--button-padding--);\n border-width: var(--button-border-width--);\n border-radius: var(--button-border-radius--);\n transition: var(--ia-button-transition--);\n\n outline-color: currentColor;\n cursor: pointer;\n line-height: normal;\n border-style: solid;\n white-space: nowrap;\n appearance: auto;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n vertical-align: middle;\n outline-offset: -4px;\n user-select: none;\n text-decoration: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n -o-user-select: none;\n }\n\n a {\n text-decoration: none;\n }\n\n button:disabled,\n button.disabled {\n cursor: not-allowed;\n color: var(--disabled-cta-text-color--);\n background-color: var(--disabled-cta-fill--);\n border: 1px solid var(--disabled-cta-border--);\n opacity: 0.5;\n }\n\n button:enabled:hover {\n opacity: 0.9;\n }\n\n button:focus-visible {\n opacity: 0.8;\n outline-style: double;\n }\n\n button:active {\n opacity: 0.7;\n }\n\n button.primary {\n color: var(--primary-cta-text-color--);\n background-color: var(--primary-cta-fill--);\n border-color: var(--primary-cta-border--);\n }\n\n button.secondary {\n color: var(--secondary-cta-text-color--);\n background-color: var(--secondary-cta-fill--);\n border-color: var(--secondary-cta-border--);\n }\n\n button.danger {\n color: var(--danger-cta-text-color--);\n background-color: var(--danger-cta-fill--);\n border-color: var(--danger-cta-border--);\n }\n\n button.warning {\n color: var(--warning-cta-text-color--);\n background-color: var(--warning-cta-fill--);\n border-color: var(--warning-cta-border--);\n }\n\n button.transparent {\n color: inherit;\n border-width: 0;\n background-color: transparent;\n border-color: transparent;\n }\n\n button.custom {\n color: var(--ia-button-custom-text-color--);\n background-color: var(--ia-button-custom-fill--);\n border-color: var(--ia-button-custom-border--);\n }\n\n button.custom:enabled:is(:hover, :focus, :active) {\n color: var(--ia-button-custom-active-text-color--);\n background-color: var(--ia-button-custom-active-fill--);\n border-color: var(--ia-button-custom-active-border--);\n }\n\n :host(.fit-content) button {\n padding: 0;\n height: fit-content;\n }\n\n button.link:enabled:hover,\n button.danger-link:enabled:hover {\n text-decoration: underline;\n }\n\n button.link,\n button.danger-link {\n margin: 0;\n border: 0;\n appearance: none;\n background: none;\n text-decoration: none;\n cursor: pointer;\n padding: 0;\n }\n\n button.link {\n color: var(--link-color--);\n }\n\n button.danger-link {\n color: var(--color-danger--);\n }\n\n .loading-indicator {\n display: flex;\n flex-direction: row;\n gap: 0.5rem;\n align-items: center;\n }\n\n ia-status-indicator {\n --ia-theme-primary-text-color: currentColor;\n }\n `,\n ];\n }\n}\n"]}
1
+ {"version":3,"file":"ia-button.js","sourceRoot":"","sources":["../../../../src/elements/ia-button/ia-button.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n html,\n LitElement,\n TemplateResult,\n CSSResultGroup,\n css,\n PropertyValues,\n render,\n} from 'lit';\nimport { msg } from '@lit/localize';\nimport { property, customElement } from 'lit/decorators.js';\nimport themeStyles from '@src/themes/theme-styles';\n\nimport '../ia-status-indicator/ia-status-indicator';\n\n/**\n * Renders a standardized button built off the ia-button styling and the activity indicator, with the option to show\n * a loading indicator instead of the text or to customize the text, and the ability to pass in any\n * function to run on click.\n *\n * Designed to behave exactly like a native type=\"submit\" or type=\"reset\" button if either type is supplied,\n * i.e. for an <ia-button type=\"submit\" @click=${doSideEffects}></ia-button>,\n * whether the form is submitted via enter or by clicking the button directly, the button will always\n * run doSideEffects() and then submit the form.\n */\n@customElement('ia-button')\nexport class IAButton extends LitElement {\n /* Which version of the button to display */\n @property({ type: String }) mode:\n | 'primary'\n | 'secondary'\n | 'danger'\n | 'warning'\n | 'disabled'\n | 'transparent'\n | 'custom'\n | 'link'\n | 'danger-link' = 'primary';\n\n /* Whether to show a loading indicator instead of the button */\n @property({ type: Boolean }) loading: boolean = false;\n\n /* Whether the button should be disabled, regardless of submission status */\n @property({ type: Boolean }) disabled: boolean = false;\n\n /* Optional text to include next to the loading indicator */\n @property({ type: String }) loadingText: string = '';\n\n /* Type of the button - defaults to 'button' to prevent form submission */\n @property({ type: String, reflect: true }) type:\n | 'button'\n | 'submit'\n | 'reset' = 'button';\n\n /* An optional href to wrap around the button */\n @property({ type: String }) href?: string;\n\n /* Whether to add a target=\"_blank\" to any wrapping link */\n @property({ type: Boolean }) openLinksNewTab: boolean = false;\n\n render(): TemplateResult {\n return html`\n ${this.href\n ? html`<a\n href=${this.href}\n target=${this.openLinksNewTab ? '_blank' : '_self'}\n >${this.buttonTemplate}</a\n >`\n : this.buttonTemplate}\n <slot name=\"hidden-button\"></slot>\n `;\n }\n\n protected willUpdate(changed: PropertyValues): void {\n if (changed.has('type')) {\n this.setButtonTypeEmulation();\n }\n }\n\n /* The native button to render */\n private get buttonTemplate(): TemplateResult {\n return html`\n <button\n part=\"button\"\n class=${this.mode}\n ?disabled=${this.disabled || this.loading}\n >\n ${this.buttonTextTemplate}\n </button>\n `;\n }\n\n /* The text to render within the button */\n private get buttonTextTemplate(): TemplateResult {\n return this.loading ? this.loadingStateTemplate : html`<slot></slot>`;\n }\n\n /* Content to render while button is loading */\n private get loadingStateTemplate(): TemplateResult {\n return html`\n <span class=\"loading-indicator\" alt=\"Loading indicator\">\n <ia-status-indicator mode=\"loading\"></ia-status-indicator> ${msg(\n this.loadingText,\n )}\n </span>\n `;\n }\n\n /** Sets up or removes button type emulation as needed */\n private setButtonTypeEmulation(): void {\n const hiddenButton: HTMLInputElement | null = this.querySelector(\n 'input.hidden-button',\n );\n\n if (hiddenButton) {\n hiddenButton.type = this.type;\n return;\n }\n\n this.addHiddenButton();\n this.addEventListener('click', this.handleComponentClick);\n }\n\n /**\n * Triggers form actions (submit/reset) on click, if desired\n * and if actions not already in progress\n */\n private handleComponentClick(e: Event): void {\n if (this.type === 'button') return;\n\n // No need to submit/reset the form if it's already submitting/resetting\n const formActionsInProgress =\n e instanceof CustomEvent && e.detail.formActionsInProgress;\n if (formActionsInProgress) return;\n\n // Request form submission/reset by clicking the hidden native submit/reset button we added earlier\n const hiddenButton = this.querySelector(\n 'input.hidden-button',\n ) as HTMLInputElement;\n hiddenButton.dispatchEvent(new PointerEvent('click'));\n }\n\n /**\n * Adds a hidden button to the light DOM to\n * emulate native reset/submit button behavior.\n *\n * Used for:\n * - Submitting/resetting the form (on behalf of handleComponentClick)\n * - Activating any component click events if form is submitted with the enter key\n * (via handleFormActions)\n */\n private addHiddenButton(): void {\n if (this.type === 'button') return;\n\n render(\n html`<input\n type=${this.type}\n class=\"hidden-button\"\n style=\"display:none\"\n slot=\"hidden-button\"\n @click=${(e: Event) => this.handleFormActions(e)}\n />`,\n this,\n );\n }\n\n /** Triggers the component's click event manually to prevent extra submission/reset */\n private handleFormActions(e: Event): void {\n /**\n * Prevents the event from bubbling up to the ia-button component itself.\n * This way, if the click on this button is triggered by a click on the component,\n * we don't accidentally bubble up a second click and end up in an infinite loop.\n *\n * And if the click was triggered by form submission (via the enter key), we can hijack the click\n * event to pass that info to the component, so it knows not to\n * re-attempt submission.\n */\n e.stopPropagation();\n\n // Detect if click comes from the parent component,\n // in which case there's no need to trigger a second click on it\n const triggeredByComponentClick = !e.isTrusted;\n if (triggeredByComponentClick) return;\n\n // Trigger parent component click events manually,\n // so it knows not to try to re-submit/re-reset the form\n this.dispatchEvent(\n new CustomEvent('click', { detail: { formActionsInProgress: true } }),\n );\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --primary-cta-text-color--: var(--primary-cta-text-color);\n --primary-cta-fill--: var(--primary-cta-fill);\n --primary-cta-border--: var(--primary-cta-border);\n\n --secondary-cta-text-color--: var(--secondary-cta-text-color);\n --secondary-cta-fill--: var(--secondary-cta-fill);\n --secondary-cta-border--: var(--secondary-cta-border);\n\n --danger-cta-text-color--: var(--danger-cta-text-color);\n --danger-cta-fill--: var(--danger-cta-fill);\n --danger-cta-border--: var(--danger-cta-border);\n\n --warning-cta-text-color--: var(--warning-cta-text-color);\n --warning-cta-fill--: var(--warning-cta-fill);\n --warning-cta-border--: var(--warning-cta-border);\n\n --disabled-cta-text-color--: var(--disabled-cta-text-color);\n --disabled-cta-fill--: var(--disabled-cta-fill);\n --disabled-cta-border--: var(--disabled-cta-border);\n\n --link-color--: var(--link-color);\n --color-danger--: var(--color-danger);\n\n --button-padding--: var(--button-padding);\n --button-width--: var(--button-width);\n --button-height--: var(--button-height);\n --button-border-width--: var(--button-border-width);\n --button-border-radius--: var(--button-border-radius);\n --base-font-family--: var(--base-font-family);\n --font-size-standard--: var(--font-size-standard);\n\n --ia-button-transition--: var(\n --ia-button-transition,\n all 0.1s ease 0s\n );\n\n --ia-button-custom-text-color--: var(\n --ia-button-custom-text-color,\n var(--primary-cta-text-color--)\n );\n --ia-button-custom-fill--: var(\n --ia-button-custom-fill,\n var(--primary-cta-fill--)\n );\n --ia-button-custom-border--: var(\n --ia-button-custom-border,\n var(--primary-cta-border--)\n );\n --ia-button-custom-active-text-color--: var(\n --ia-button-custom-active-text-color,\n var(--ia-button-custom-text-color--)\n );\n --ia-button-custom-active-fill--: var(\n --ia-button-custom-active-fill,\n var(--ia-button-custom-fill--)\n );\n --ia-button-custom-active-border--: var(\n --ia-button-custom-active-border,\n var(--ia-button-custom-border--)\n );\n\n display: inline-block; /* keeps host sized to button */\n }\n\n button {\n font-family: var(--base-font-family--);\n font-size: var(--font-size-standard--);\n height: var(--button-height--);\n min-height: var(--button-height--);\n width: var(--button-width--);\n padding: var(--button-padding--);\n border-width: var(--button-border-width--);\n border-radius: var(--button-border-radius--);\n transition: var(--ia-button-transition--);\n\n outline-color: currentColor;\n cursor: pointer;\n line-height: normal;\n border-style: solid;\n white-space: nowrap;\n appearance: auto;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n vertical-align: middle;\n outline-offset: -4px;\n user-select: none;\n text-decoration: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n -o-user-select: none;\n }\n\n a {\n text-decoration: none;\n }\n\n button:disabled,\n button.disabled {\n cursor: not-allowed;\n color: var(--disabled-cta-text-color--);\n background-color: var(--disabled-cta-fill--);\n border: 1px solid var(--disabled-cta-border--);\n opacity: 0.5;\n }\n\n button:enabled:hover {\n opacity: 0.9;\n }\n\n button:focus-visible {\n opacity: 0.8;\n outline-style: double;\n }\n\n button:active {\n opacity: 0.7;\n }\n\n button.primary {\n color: var(--primary-cta-text-color--);\n background-color: var(--primary-cta-fill--);\n border-color: var(--primary-cta-border--);\n }\n\n button.secondary {\n color: var(--secondary-cta-text-color--);\n background-color: var(--secondary-cta-fill--);\n border-color: var(--secondary-cta-border--);\n }\n\n button.danger {\n color: var(--danger-cta-text-color--);\n background-color: var(--danger-cta-fill--);\n border-color: var(--danger-cta-border--);\n }\n\n button.warning {\n color: var(--warning-cta-text-color--);\n background-color: var(--warning-cta-fill--);\n border-color: var(--warning-cta-border--);\n }\n\n button.transparent {\n color: inherit;\n border-width: 0;\n background-color: transparent;\n border-color: transparent;\n }\n\n button.custom {\n color: var(--ia-button-custom-text-color--);\n background-color: var(--ia-button-custom-fill--);\n border-color: var(--ia-button-custom-border--);\n }\n\n button.custom:enabled:is(:hover, :focus, :active, .active) {\n color: var(--ia-button-custom-active-text-color--);\n background-color: var(--ia-button-custom-active-fill--);\n border-color: var(--ia-button-custom-active-border--);\n }\n\n :host(.fit-content) button {\n padding: 0;\n height: fit-content;\n }\n\n button.link:enabled:hover,\n button.danger-link:enabled:hover {\n text-decoration: underline;\n }\n\n button.link,\n button.danger-link {\n margin: 0;\n border: 0;\n appearance: none;\n background: none;\n text-decoration: none;\n cursor: pointer;\n padding: 0;\n }\n\n button.link {\n color: var(--link-color--);\n }\n\n button.danger-link {\n color: var(--color-danger--);\n }\n\n .loading-indicator {\n display: flex;\n flex-direction: row;\n gap: 0.5rem;\n align-items: center;\n }\n\n ia-status-indicator {\n --ia-theme-primary-text-color: currentColor;\n }\n `,\n ];\n }\n}\n"]}
@@ -2,6 +2,7 @@ import { LitElement, TemplateResult, CSSResultGroup, PropertyValues } from 'lit'
2
2
  import type { LoadingStatus } from '../../elements/ia-status-indicator/ia-status-indicator.js';
3
3
  import '../../elements/ia-status-indicator/ia-status-indicator.js';
4
4
  import '../../elements/ia-otp-input/ia-otp-input.js';
5
+ import '../../elements/ia-button/ia-button.js';
5
6
  /**
6
7
  * Form for entering OTP codes, including success/loading/error states and a request new code button
7
8
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ia-otp-form.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-otp-form/ia-otp-form.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EACV,cAAc,EACd,cAAc,EAGd,cAAc,EACf,MAAM,KAAK,CAAC;AAOb,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uDAAuD,CAAC;AAE3F,OAAO,uDAAuD,CAAC;AAC/D,OAAO,yCAAyC,CAAC;AAUjD;;GAEG;AACH,qBACa,SAAU,SAAQ,UAAU;IAGvC,gBAAgB,EAAE,aAAa,CAAW;IAI1C,cAAc,EAAE,OAAO,CAAS;IAIhC,gBAAgB,EAAE,MAAM,CAAK;IAI7B,WAAW,EAAE,OAAO,CAAQ;IAG5B,OAAO,CAAC,QAAQ,CAAc;IAE9B,MAAM,IAAI,cAAc;IAuBxB,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAenD,OAAO,KAAK,wBAAwB,GAgBnC;YAGa,sBAAsB;IAUpC,MAAM,KAAK,MAAM,IAAI,cAAc,CAkElC;CACF"}
1
+ {"version":3,"file":"ia-otp-form.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-otp-form/ia-otp-form.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EACV,cAAc,EACd,cAAc,EAGd,cAAc,EACf,MAAM,KAAK,CAAC;AAOb,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uDAAuD,CAAC;AAE3F,OAAO,uDAAuD,CAAC;AAC/D,OAAO,yCAAyC,CAAC;AACjD,OAAO,mCAAmC,CAAC;AAU3C;;GAEG;AACH,qBACa,SAAU,SAAQ,UAAU;IAGvC,gBAAgB,EAAE,aAAa,CAAW;IAI1C,cAAc,EAAE,OAAO,CAAS;IAIhC,gBAAgB,EAAE,MAAM,CAAK;IAI7B,WAAW,EAAE,OAAO,CAAQ;IAG5B,OAAO,CAAC,QAAQ,CAAc;IAE9B,MAAM,IAAI,cAAc;IAuBxB,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAenD,OAAO,KAAK,wBAAwB,GAiBnC;YAGa,sBAAsB;IAUpC,MAAM,KAAK,MAAM,IAAI,cAAc,CA8ClC;CACF"}
@@ -5,6 +5,7 @@ import { property, customElement, query } from 'lit/decorators.js';
5
5
  import themeStyles from '../../themes/theme-styles.js';
6
6
  import '../../elements/ia-status-indicator/ia-status-indicator.js';
7
7
  import '../../elements/ia-otp-input/ia-otp-input.js';
8
+ import '../../elements/ia-button/ia-button.js';
8
9
  /**
9
10
  * Custom events fired by the component
10
11
  */
@@ -66,15 +67,16 @@ let IAOTPForm = class IAOTPForm extends LitElement {
66
67
  >${msg('Emailing...')}</span
67
68
  >`
68
69
  : html `
69
- <button
70
- class="new-code-btn link"
70
+ <ia-button
71
+ mode="link"
72
+ class="new-code-btn"
71
73
  part="new-code-button"
72
74
  .disabled=${this.validationStatus === 'loading' ||
73
75
  this.validationStatus === 'success'}
74
76
  @click=${this.handleNewCodeRequested}
75
77
  >
76
78
  ${msg('Email me another code')}
77
- </button>
79
+ </ia-button>
78
80
  `;
79
81
  }
80
82
  /* Emits an event to request the new code */
@@ -121,26 +123,6 @@ let IAOTPForm = class IAOTPForm extends LitElement {
121
123
  margin-bottom: -10px;
122
124
  }
123
125
 
124
- .new-code-btn {
125
- font-family: inherit;
126
- font-size: var(--font-size-standard--);
127
- display: block;
128
- width: fit-content;
129
- margin-top: 10px;
130
- border: 0;
131
- padding: 0;
132
- appearance: none;
133
- background: none;
134
- color: var(--link-color--);
135
- text-decoration: none;
136
- cursor: pointer;
137
- }
138
-
139
- .new-code-btn:hover,
140
- .new-code-btn:focus {
141
- text-decoration: underline;
142
- }
143
-
144
126
  .new-code-msg {
145
127
  margin-top: 10px;
146
128
  font-size: var(--font-size-standard--);
@@ -1 +1 @@
1
- {"version":3,"file":"ia-otp-form.js","sourceRoot":"","sources":["../../../../src/elements/ia-otp-form/ia-otp-form.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n html,\n LitElement,\n TemplateResult,\n CSSResultGroup,\n css,\n nothing,\n PropertyValues,\n} from 'lit';\nimport { msg } from '@lit/localize';\nimport { property, customElement, query } from 'lit/decorators.js';\n\nimport themeStyles from '@src/themes/theme-styles';\n\nimport type { IAOTPInput } from '@src/elements/ia-otp-input/ia-otp-input';\nimport type { LoadingStatus } from '@src/elements/ia-status-indicator/ia-status-indicator';\n\nimport '@src/elements/ia-status-indicator/ia-status-indicator';\nimport '@src/elements/ia-otp-input/ia-otp-input';\n\n/**\n * Custom events fired by the component\n */\nconst Events = {\n NewCodeRequested: 'newCodeRequested',\n CodeSubmitted: 'codeSubmitted', // Bubbles up from ia-otp-input\n};\n\n/**\n * Form for entering OTP codes, including success/loading/error states and a request new code button\n */\n@customElement('ia-otp-form')\nexport class IAOTPForm extends LitElement {\n /* The state of the validation process */\n @property({ type: String })\n validationStatus: LoadingStatus = 'ready';\n\n /* Whether to display a loading indicator instead of the button text */\n @property({ type: Boolean })\n newCodeSending: boolean = false;\n\n /* Number of characters to expect for the passcode */\n @property({ type: Number })\n numPasscodeChars: number = 6;\n\n /* Whether to restrict entry to numeric characters */\n @property({ type: Boolean })\n numericOnly: boolean = true;\n\n @query('ia-otp-input')\n private OTPInput!: IAOTPInput;\n\n render(): TemplateResult {\n return html`\n <div class=\"input-section\">\n <ia-otp-input\n .numChars=${this.numPasscodeChars}\n ?numericOnly=${this.numericOnly}\n ?disabled=${this.validationStatus === 'loading' ||\n this.validationStatus === 'success'}\n ></ia-otp-input>\n <ia-status-indicator\n part=\"status-indicator\"\n .mode=${this.validationStatus}\n ></ia-status-indicator>\n </div>\n ${this.validationStatus === 'error'\n ? html`<p class=\"error-msg\">\n ${msg('The code entered is invalid or expired')}\n </p>`\n : nothing}\n ${this.resendCodeButtonTemplate}\n `;\n }\n\n protected willUpdate(changed: PropertyValues): void {\n if (\n changed.has('validationStatus') &&\n this.OTPInput &&\n this.validationStatus === 'error'\n ) {\n this.OTPInput.prefillValue = '';\n }\n\n if (changed.has('newCodeSending') && this.newCodeSending && this.OTPInput) {\n this.OTPInput.prefillValue = '';\n }\n }\n\n /* The button to display to send a new code */\n private get resendCodeButtonTemplate(): TemplateResult {\n return this.newCodeSending\n ? html`<span part=\"new-code-message\" class=\"new-code-msg\"\n >${msg('Emailing...')}</span\n >`\n : html`\n <button\n class=\"new-code-btn link\"\n part=\"new-code-button\"\n .disabled=${this.validationStatus === 'loading' ||\n this.validationStatus === 'success'}\n @click=${this.handleNewCodeRequested}\n >\n ${msg('Email me another code')}\n </button>\n `;\n }\n\n /* Emits an event to request the new code */\n private async handleNewCodeRequested(): Promise<void> {\n this.dispatchEvent(\n new CustomEvent(Events.NewCodeRequested, {\n bubbles: true,\n composed: true,\n }),\n );\n this.OTPInput.prefillValue = '';\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --font-size-standard--: var(--font-size-standard);\n --font-size-lg--: var(--font-size-lg);\n --color-success--: var(--color-success);\n --color-danger--: var(--color-danger);\n --link-color--: var(--link-color);\n\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n }\n\n .input-section {\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n gap: 5px;\n }\n\n ia-status-indicator {\n --icon-width: calc(var(--font-size-lg--) * 1.33);\n }\n\n .error-msg {\n margin-top: 10px;\n font-size: var(--font-size-standard--);\n color: var(--color-danger--);\n margin-bottom: -10px;\n }\n\n .new-code-btn {\n font-family: inherit;\n font-size: var(--font-size-standard--);\n display: block;\n width: fit-content;\n margin-top: 10px;\n border: 0;\n padding: 0;\n appearance: none;\n background: none;\n color: var(--link-color--);\n text-decoration: none;\n cursor: pointer;\n }\n\n .new-code-btn:hover,\n .new-code-btn:focus {\n text-decoration: underline;\n }\n\n .new-code-msg {\n margin-top: 10px;\n font-size: var(--font-size-standard--);\n color: var(--link-color--);\n display: flex;\n flex-direction: column;\n justify-content: center;\n }\n `,\n ];\n }\n}\n"]}
1
+ {"version":3,"file":"ia-otp-form.js","sourceRoot":"","sources":["../../../../src/elements/ia-otp-form/ia-otp-form.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n html,\n LitElement,\n TemplateResult,\n CSSResultGroup,\n css,\n nothing,\n PropertyValues,\n} from 'lit';\nimport { msg } from '@lit/localize';\nimport { property, customElement, query } from 'lit/decorators.js';\n\nimport themeStyles from '@src/themes/theme-styles';\n\nimport type { IAOTPInput } from '@src/elements/ia-otp-input/ia-otp-input';\nimport type { LoadingStatus } from '@src/elements/ia-status-indicator/ia-status-indicator';\n\nimport '@src/elements/ia-status-indicator/ia-status-indicator';\nimport '@src/elements/ia-otp-input/ia-otp-input';\nimport '@src/elements/ia-button/ia-button';\n\n/**\n * Custom events fired by the component\n */\nconst Events = {\n NewCodeRequested: 'newCodeRequested',\n CodeSubmitted: 'codeSubmitted', // Bubbles up from ia-otp-input\n};\n\n/**\n * Form for entering OTP codes, including success/loading/error states and a request new code button\n */\n@customElement('ia-otp-form')\nexport class IAOTPForm extends LitElement {\n /* The state of the validation process */\n @property({ type: String })\n validationStatus: LoadingStatus = 'ready';\n\n /* Whether to display a loading indicator instead of the button text */\n @property({ type: Boolean })\n newCodeSending: boolean = false;\n\n /* Number of characters to expect for the passcode */\n @property({ type: Number })\n numPasscodeChars: number = 6;\n\n /* Whether to restrict entry to numeric characters */\n @property({ type: Boolean })\n numericOnly: boolean = true;\n\n @query('ia-otp-input')\n private OTPInput!: IAOTPInput;\n\n render(): TemplateResult {\n return html`\n <div class=\"input-section\">\n <ia-otp-input\n .numChars=${this.numPasscodeChars}\n ?numericOnly=${this.numericOnly}\n ?disabled=${this.validationStatus === 'loading' ||\n this.validationStatus === 'success'}\n ></ia-otp-input>\n <ia-status-indicator\n part=\"status-indicator\"\n .mode=${this.validationStatus}\n ></ia-status-indicator>\n </div>\n ${this.validationStatus === 'error'\n ? html`<p class=\"error-msg\">\n ${msg('The code entered is invalid or expired')}\n </p>`\n : nothing}\n ${this.resendCodeButtonTemplate}\n `;\n }\n\n protected willUpdate(changed: PropertyValues): void {\n if (\n changed.has('validationStatus') &&\n this.OTPInput &&\n this.validationStatus === 'error'\n ) {\n this.OTPInput.prefillValue = '';\n }\n\n if (changed.has('newCodeSending') && this.newCodeSending && this.OTPInput) {\n this.OTPInput.prefillValue = '';\n }\n }\n\n /* The button to display to send a new code */\n private get resendCodeButtonTemplate(): TemplateResult {\n return this.newCodeSending\n ? html`<span part=\"new-code-message\" class=\"new-code-msg\"\n >${msg('Emailing...')}</span\n >`\n : html`\n <ia-button\n mode=\"link\"\n class=\"new-code-btn\"\n part=\"new-code-button\"\n .disabled=${this.validationStatus === 'loading' ||\n this.validationStatus === 'success'}\n @click=${this.handleNewCodeRequested}\n >\n ${msg('Email me another code')}\n </ia-button>\n `;\n }\n\n /* Emits an event to request the new code */\n private async handleNewCodeRequested(): Promise<void> {\n this.dispatchEvent(\n new CustomEvent(Events.NewCodeRequested, {\n bubbles: true,\n composed: true,\n }),\n );\n this.OTPInput.prefillValue = '';\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --font-size-standard--: var(--font-size-standard);\n --font-size-lg--: var(--font-size-lg);\n --color-success--: var(--color-success);\n --color-danger--: var(--color-danger);\n --link-color--: var(--link-color);\n\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n }\n\n .input-section {\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n gap: 5px;\n }\n\n ia-status-indicator {\n --icon-width: calc(var(--font-size-lg--) * 1.33);\n }\n\n .error-msg {\n margin-top: 10px;\n font-size: var(--font-size-standard--);\n color: var(--color-danger--);\n margin-bottom: -10px;\n }\n\n .new-code-msg {\n margin-top: 10px;\n font-size: var(--font-size-standard--);\n color: var(--link-color--);\n display: flex;\n flex-direction: column;\n justify-content: center;\n }\n `,\n ];\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ia-otp-input.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-otp-input/ia-otp-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EACV,cAAc,EACd,cAAc,EAEd,cAAc,EACf,MAAM,KAAK,CAAC;AAcb;;;;GAIG;AACH,qBACa,UAAW,SAAQ,UAAU;IAGxC,YAAY,CAAC,EAAE,MAAM,CAAC;IAItB,QAAQ,EAAE,OAAO,CAAS;IAI1B,QAAQ,EAAE,MAAM,CAAK;IAIrB,WAAW,EAAE,OAAO,CAAQ;IAI5B,OAAO,CAAC,YAAY,CAAyB;IAI7C,OAAO,CAAC,MAAM,CAAgC;IAE9C,MAAM,IAAI,cAAc;IAmBxB,SAAS,CAAC,YAAY,IAAI,IAAI;IAI9B,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAYnD,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,aAAa;IAmCrB;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAuBlB,yDAAyD;IACzD,OAAO,CAAC,WAAW;IAKnB,6DAA6D;IAC7D,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,aAAa;IAUrB,MAAM,KAAK,MAAM,IAAI,cAAc,CA4BlC;CACF"}
1
+ {"version":3,"file":"ia-otp-input.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-otp-input/ia-otp-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EACV,cAAc,EACd,cAAc,EAEd,cAAc,EACf,MAAM,KAAK,CAAC;AAcb;;;;GAIG;AACH,qBACa,UAAW,SAAQ,UAAU;IAGxC,YAAY,CAAC,EAAE,MAAM,CAAC;IAItB,QAAQ,EAAE,OAAO,CAAS;IAI1B,QAAQ,EAAE,MAAM,CAAK;IAIrB,WAAW,EAAE,OAAO,CAAQ;IAI5B,OAAO,CAAC,YAAY,CAAyB;IAI7C,OAAO,CAAC,MAAM,CAAgC;IAE9C,MAAM,IAAI,cAAc;IAmBxB,SAAS,CAAC,YAAY,IAAI,IAAI;IAI9B,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAYnD,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,aAAa;IAmCrB;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAyBlB,yDAAyD;IACzD,OAAO,CAAC,WAAW;IAKnB,6DAA6D;IAC7D,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,aAAa;IAUrB,MAAM,KAAK,MAAM,IAAI,cAAc,CA4BlC;CACF"}
@@ -122,6 +122,8 @@ let IAOTPInput = class IAOTPInput extends LitElement {
122
122
  * Submits the result if enough characters are filled.
123
123
  */
124
124
  fillInputs(value) {
125
+ if (typeof value !== 'string')
126
+ value = String(value ?? '');
125
127
  if (value === '')
126
128
  this.clearInputs();
127
129
  const charsToFill = value
@@ -1 +1 @@
1
- {"version":3,"file":"ia-otp-input.js","sourceRoot":"","sources":["../../../../src/elements/ia-otp-input/ia-otp-input.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n html,\n LitElement,\n TemplateResult,\n CSSResultGroup,\n css,\n PropertyValues,\n} from 'lit';\nimport { property, customElement, queryAll } from 'lit/decorators.js';\nimport themeStyles from '@src/themes/theme-styles';\n\n/**\n * Custom event options for the component\n */\nconst Events = {\n CodeSubmitted: 'codeSubmitted',\n};\n\nconst NUMERIC_REGEX = /^[0-9]+$/;\nconst ALPHANUMERIC_REGEX = /^[a-zA-Z0-9]+$/;\n\n/**\n * Renders an input for OTP entry, which combines a series of separate\n * inputs into one, shifting focus as needed and handling paste and backspace\n * events.\n */\n@customElement('ia-otp-input')\nexport class IAOTPInput extends LitElement {\n /* An optional value to prefill the inputs with */\n @property({ type: String })\n prefillValue?: string;\n\n /* Whether to disable all inputs */\n @property({ type: Boolean })\n disabled: boolean = false;\n\n /* Number of characters to expect for the passcode */\n @property({ type: Number })\n numChars: number = 6;\n\n /* Whether to restrict entry to numeric characters */\n @property({ type: Boolean })\n numericOnly: boolean = true;\n\n /* Regex for allowed characters. Updates based on numeric only */\n @property({ type: Object })\n private allowedChars: RegExp = NUMERIC_REGEX;\n\n /* Array of OTP inputs */\n @queryAll('input')\n private inputs!: NodeListOf<HTMLInputElement>;\n\n render(): TemplateResult {\n return html`\n ${[...Array(this.numChars).keys()].map(\n (i) =>\n html`<input\n id=\"OTP-input-${i}\"\n part=\"input\"\n type=\"text\"\n autocomplete=${i === 0 ? 'one-time-code' : 'off'}\n inputmode=${this.numericOnly ? 'numeric' : 'text'}\n ?disabled=${this.disabled}\n @beforeinput=${this.handleInput}\n @paste=${this.handlePaste}\n @keydown=${this.handleKeydown}\n />`,\n )}\n `;\n }\n\n protected firstUpdated(): void {\n this.inputs[0].focus();\n }\n\n protected willUpdate(changed: PropertyValues): void {\n if (changed.has('numericOnly')) {\n this.allowedChars = this.numericOnly ? NUMERIC_REGEX : ALPHANUMERIC_REGEX;\n }\n\n if (changed.has('prefillValue') && this.prefillValue !== undefined) {\n this.fillInputs(this.prefillValue);\n this.prefillValue = undefined;\n }\n }\n\n /* Shifts forward on input */\n private handleInput(e: InputEvent): void {\n e.preventDefault();\n const input = e.target as HTMLInputElement;\n const addedValue = e.data;\n\n if (!addedValue) return;\n if (addedValue.length > 1) {\n this.fillInputs(addedValue);\n return;\n }\n if (!this.allowedChars.test(addedValue)) return;\n\n input.value = addedValue;\n const next = input.nextElementSibling as HTMLInputElement;\n if (next) next.focus();\n\n this.submitIfInputsFilled();\n }\n\n /* Performs special actions associated with some keys */\n private handleKeydown(e: KeyboardEvent): void {\n const input = e.target as HTMLInputElement;\n const key = e.key;\n const prev = input.previousElementSibling as HTMLInputElement;\n const next = input.nextElementSibling as HTMLInputElement;\n\n switch (key) {\n case 'Backspace':\n case 'Delete':\n e.preventDefault();\n if (prev) prev.focus();\n\n if (input.value === '') {\n prev.value = '';\n break;\n }\n\n input.value = '';\n break;\n case 'Tab':\n input.select();\n break;\n case 'ArrowRight':\n case 'Right':\n e.preventDefault();\n if (next) next.focus();\n break;\n case 'ArrowLeft':\n case 'Left':\n e.preventDefault();\n if (prev) prev.focus();\n break;\n }\n }\n\n /**\n * Transmits pasted data to the input-filling function\n */\n private handlePaste(e: ClipboardEvent): void {\n e.preventDefault();\n\n const pastedText = e.clipboardData?.getData('text');\n if (pastedText) this.fillInputs(pastedText);\n }\n\n /**\n * Fills as many inputs as possible with the specified value, starting from the beginning.\n * Submits the result if enough characters are filled.\n */\n private fillInputs(value: string) {\n if (value === '') this.clearInputs();\n\n const charsToFill = value\n .split('')\n .filter((char) => this.allowedChars.test(char))\n .slice(0, this.numChars);\n\n if (!charsToFill || charsToFill.length === 0) return;\n charsToFill.forEach(\n (char, i) => ((this.inputs[i] as HTMLInputElement).value = char),\n );\n\n if (charsToFill.length === this.numChars) {\n this.triggerSubmit(charsToFill.join(''));\n this.inputs[this.numChars - 1].focus();\n return;\n }\n\n const next = this.inputs[charsToFill.length];\n next.focus();\n }\n\n /** Clears all inputs and returns focus to first input */\n private clearInputs(): void {\n this.inputs.forEach((input) => (input.value = ''));\n this.inputs[0].focus();\n }\n\n /** Checks whether all inputs are filled and submits if so */\n private submitIfInputsFilled(): void {\n const code: string[] = [];\n this.inputs.forEach((input) => {\n if (input.value) code.push(input.value);\n });\n\n if (code.length === this.numChars) this.triggerSubmit(code.join(''));\n }\n\n /* Submits code */\n private triggerSubmit(code: string): void {\n this.dispatchEvent(\n new CustomEvent(Events.CodeSubmitted, {\n detail: this.numericOnly ? code : code.toUpperCase(),\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --primary-text-color--: var(--primary-text-color);\n --font-size-lg--: var(--font-size-lg);\n }\n\n :host {\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n gap: 5px;\n }\n\n input {\n color: var(--primary-text-color--);\n font-size: var(--font-size-lg--);\n width: var(--font-size-lg--);\n font-weight: bold;\n height: calc(var(--font-size-lg--) + 1.25rem);\n text-align: center;\n text-transform: uppercase;\n padding: 0;\n }\n `,\n ];\n }\n}\n"]}
1
+ {"version":3,"file":"ia-otp-input.js","sourceRoot":"","sources":["../../../../src/elements/ia-otp-input/ia-otp-input.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n html,\n LitElement,\n TemplateResult,\n CSSResultGroup,\n css,\n PropertyValues,\n} from 'lit';\nimport { property, customElement, queryAll } from 'lit/decorators.js';\nimport themeStyles from '@src/themes/theme-styles';\n\n/**\n * Custom event options for the component\n */\nconst Events = {\n CodeSubmitted: 'codeSubmitted',\n};\n\nconst NUMERIC_REGEX = /^[0-9]+$/;\nconst ALPHANUMERIC_REGEX = /^[a-zA-Z0-9]+$/;\n\n/**\n * Renders an input for OTP entry, which combines a series of separate\n * inputs into one, shifting focus as needed and handling paste and backspace\n * events.\n */\n@customElement('ia-otp-input')\nexport class IAOTPInput extends LitElement {\n /* An optional value to prefill the inputs with */\n @property({ type: String })\n prefillValue?: string;\n\n /* Whether to disable all inputs */\n @property({ type: Boolean })\n disabled: boolean = false;\n\n /* Number of characters to expect for the passcode */\n @property({ type: Number })\n numChars: number = 6;\n\n /* Whether to restrict entry to numeric characters */\n @property({ type: Boolean })\n numericOnly: boolean = true;\n\n /* Regex for allowed characters. Updates based on numeric only */\n @property({ type: Object })\n private allowedChars: RegExp = NUMERIC_REGEX;\n\n /* Array of OTP inputs */\n @queryAll('input')\n private inputs!: NodeListOf<HTMLInputElement>;\n\n render(): TemplateResult {\n return html`\n ${[...Array(this.numChars).keys()].map(\n (i) =>\n html`<input\n id=\"OTP-input-${i}\"\n part=\"input\"\n type=\"text\"\n autocomplete=${i === 0 ? 'one-time-code' : 'off'}\n inputmode=${this.numericOnly ? 'numeric' : 'text'}\n ?disabled=${this.disabled}\n @beforeinput=${this.handleInput}\n @paste=${this.handlePaste}\n @keydown=${this.handleKeydown}\n />`,\n )}\n `;\n }\n\n protected firstUpdated(): void {\n this.inputs[0].focus();\n }\n\n protected willUpdate(changed: PropertyValues): void {\n if (changed.has('numericOnly')) {\n this.allowedChars = this.numericOnly ? NUMERIC_REGEX : ALPHANUMERIC_REGEX;\n }\n\n if (changed.has('prefillValue') && this.prefillValue !== undefined) {\n this.fillInputs(this.prefillValue);\n this.prefillValue = undefined;\n }\n }\n\n /* Shifts forward on input */\n private handleInput(e: InputEvent): void {\n e.preventDefault();\n const input = e.target as HTMLInputElement;\n const addedValue = e.data;\n\n if (!addedValue) return;\n if (addedValue.length > 1) {\n this.fillInputs(addedValue);\n return;\n }\n if (!this.allowedChars.test(addedValue)) return;\n\n input.value = addedValue;\n const next = input.nextElementSibling as HTMLInputElement;\n if (next) next.focus();\n\n this.submitIfInputsFilled();\n }\n\n /* Performs special actions associated with some keys */\n private handleKeydown(e: KeyboardEvent): void {\n const input = e.target as HTMLInputElement;\n const key = e.key;\n const prev = input.previousElementSibling as HTMLInputElement;\n const next = input.nextElementSibling as HTMLInputElement;\n\n switch (key) {\n case 'Backspace':\n case 'Delete':\n e.preventDefault();\n if (prev) prev.focus();\n\n if (input.value === '') {\n prev.value = '';\n break;\n }\n\n input.value = '';\n break;\n case 'Tab':\n input.select();\n break;\n case 'ArrowRight':\n case 'Right':\n e.preventDefault();\n if (next) next.focus();\n break;\n case 'ArrowLeft':\n case 'Left':\n e.preventDefault();\n if (prev) prev.focus();\n break;\n }\n }\n\n /**\n * Transmits pasted data to the input-filling function\n */\n private handlePaste(e: ClipboardEvent): void {\n e.preventDefault();\n\n const pastedText = e.clipboardData?.getData('text');\n if (pastedText) this.fillInputs(pastedText);\n }\n\n /**\n * Fills as many inputs as possible with the specified value, starting from the beginning.\n * Submits the result if enough characters are filled.\n */\n private fillInputs(value: string) {\n if (typeof value !== 'string') value = String(value ?? '');\n\n if (value === '') this.clearInputs();\n\n const charsToFill = value\n .split('')\n .filter((char) => this.allowedChars.test(char))\n .slice(0, this.numChars);\n\n if (!charsToFill || charsToFill.length === 0) return;\n charsToFill.forEach(\n (char, i) => ((this.inputs[i] as HTMLInputElement).value = char),\n );\n\n if (charsToFill.length === this.numChars) {\n this.triggerSubmit(charsToFill.join(''));\n this.inputs[this.numChars - 1].focus();\n return;\n }\n\n const next = this.inputs[charsToFill.length];\n next.focus();\n }\n\n /** Clears all inputs and returns focus to first input */\n private clearInputs(): void {\n this.inputs.forEach((input) => (input.value = ''));\n this.inputs[0].focus();\n }\n\n /** Checks whether all inputs are filled and submits if so */\n private submitIfInputsFilled(): void {\n const code: string[] = [];\n this.inputs.forEach((input) => {\n if (input.value) code.push(input.value);\n });\n\n if (code.length === this.numChars) this.triggerSubmit(code.join(''));\n }\n\n /* Submits code */\n private triggerSubmit(code: string): void {\n this.dispatchEvent(\n new CustomEvent(Events.CodeSubmitted, {\n detail: this.numericOnly ? code : code.toUpperCase(),\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --primary-text-color--: var(--primary-text-color);\n --font-size-lg--: var(--font-size-lg);\n }\n\n :host {\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n gap: 5px;\n }\n\n input {\n color: var(--primary-text-color--);\n font-size: var(--font-size-lg--);\n width: var(--font-size-lg--);\n font-weight: bold;\n height: calc(var(--font-size-lg--) + 1.25rem);\n text-align: center;\n text-transform: uppercase;\n padding: 0;\n }\n `,\n ];\n }\n}\n"]}
@@ -7,7 +7,7 @@ export declare class IASnow extends LitElement {
7
7
  snowConfig?: SnowflakesParams;
8
8
  private snowing;
9
9
  private snowflakes?;
10
- render(): import("lit-html").TemplateResult<1>;
10
+ render(): import("lit").TemplateResult<1>;
11
11
  protected willUpdate(_changedProperties: PropertyValues): void;
12
12
  private get startButtonTemplate();
13
13
  private get clearButtonTemplate();
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "@internetarchive/elements",
3
- "version": "0.2.10",
3
+ "version": "0.2.12-rc.0",
4
4
  "description": "A web component library from the Internet Archive.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "types": "./dist/src/elements/index.d.ts",
7
7
  "type": "module",
8
+ "packageManager": "pnpm@11.20.0",
9
+ "engines": {
10
+ "node": ">=24",
11
+ "pnpm": ">=11"
12
+ },
8
13
  "publishConfig": {
9
14
  "access": "public"
10
15
  },
@@ -35,8 +40,11 @@
35
40
  "tslib": "^2.8.1"
36
41
  },
37
42
  "devDependencies": {
43
+ "@eslint/eslintrc": "^3.3.5",
44
+ "@eslint/js": "^9.39.1",
38
45
  "@open-wc/testing-helpers": "^3.0.1",
39
46
  "@typescript-eslint/eslint-plugin": "^8.46.4",
47
+ "@typescript-eslint/parser": "^8.46.4",
40
48
  "@vitest/browser": "^4.0.8",
41
49
  "@vitest/browser-playwright": "^4.0.8",
42
50
  "@vitest/coverage-v8": "^4.0.8",
@@ -51,7 +59,7 @@
51
59
  "highlight.js": "^11.11.1",
52
60
  "madge": "^8.0.0",
53
61
  "playwright": "^1.60.0",
54
- "prettier": "^3.6.2",
62
+ "prettier": "3.6.2",
55
63
  "ts-lit-plugin": "^2.0.2",
56
64
  "tsc-alias": "^1.8.16",
57
65
  "typescript": "^5.9.3",