diff --git a/frontend/code/components/dropdown.ts b/frontend/code/components/dropdown.ts index ae4c9ed9..ec4ea67a 100644 --- a/frontend/code/components/dropdown.ts +++ b/frontend/code/components/dropdown.ts @@ -32,7 +32,7 @@ export class DropdownComponent extends ComponentBase { element.classList.add('rio-dropdown'); // The dropdown is styled as an input box. Use the InputBox abstraction - this.inputBox = new InputBox({ labelIsAlwaysSmall: true }); + this.inputBox = new InputBox(this.id, { labelIsAlwaysSmall: true }); element.appendChild(this.inputBox.outerElement); // In order to ensure the dropdown can actually fit its options, add a diff --git a/frontend/code/components/image.ts b/frontend/code/components/image.ts index 6fd09c6c..a7dba87e 100644 --- a/frontend/code/components/image.ts +++ b/frontend/code/components/image.ts @@ -23,6 +23,7 @@ export class ImageComponent extends ComponentBase { createElement(): HTMLElement { let element = document.createElement('div'); element.classList.add('rio-image'); + element.role = 'img'; this.imageElement = document.createElement('img'); element.appendChild(this.imageElement); diff --git a/frontend/code/components/multiLineTextInput.ts b/frontend/code/components/multiLineTextInput.ts index 0c4afe28..3404d0f6 100644 --- a/frontend/code/components/multiLineTextInput.ts +++ b/frontend/code/components/multiLineTextInput.ts @@ -17,7 +17,7 @@ export class MultiLineTextInputComponent extends ComponentBase { createElement(): HTMLElement { let textarea = document.createElement('textarea'); - this.inputBox = new InputBox({ inputElement: textarea }); + this.inputBox = new InputBox(this.id, { inputElement: textarea }); let element = this.inputBox.outerElement; element.classList.add('rio-multi-line-text-input'); diff --git a/frontend/code/components/switcher.ts b/frontend/code/components/switcher.ts index 49d03757..7bfa6872 100644 --- a/frontend/code/components/switcher.ts +++ b/frontend/code/components/switcher.ts @@ -15,6 +15,7 @@ export class SwitcherComponent extends ComponentBase { private activeChildContainer: HTMLElement | null = null; private resizerElement: HTMLElement | null = null; private idOfCurrentAnimation: number = 0; + private isInitialized: boolean = false; createElement(): HTMLElement { let element = document.createElement('div'); @@ -38,16 +39,30 @@ export class SwitcherComponent extends ComponentBase { } // Update the child - if ( - deltaState.content !== undefined && - deltaState.content !== this.state.content - ) { - this.replaceContent( - deltaState.content, - latentComponents, - deltaState.transition_time ?? this.state.transition_time - ); + if (deltaState.content !== undefined) { + if (!this.isInitialized) { + // When it's the first time, don't animate + this.activeChildContainer = document.createElement('div'); + this.activeChildContainer.classList.add( + 'rio-switcher-active-child' + ); + this.element.appendChild(this.activeChildContainer); + + this.replaceOnlyChild( + latentComponents, + deltaState.content, + this.activeChildContainer + ); + } else if (deltaState.content !== this.state.content) { + this.replaceContent( + deltaState.content, + latentComponents, + deltaState.transition_time ?? this.state.transition_time + ); + } } + + this.isInitialized = true; } private async replaceContent( @@ -104,8 +119,6 @@ export class SwitcherComponent extends ComponentBase { if (content !== null) { // Add the child into a helper container newChildContainer = document.createElement('div'); - newChildContainer.classList.add('rio-switcher-active-child'); - this.replaceOnlyChild(latentComponents, content, newChildContainer); // Make it `absolute` so it isn't influenced by the Switcher's @@ -128,6 +141,10 @@ export class SwitcherComponent extends ComponentBase { newChildContainer.style.removeProperty('position'); newChildContainer.style.removeProperty('width'); + + commitCss(newChildContainer); + + newChildContainer.classList.add('rio-switcher-active-child'); } this.activeChildContainer = newChildContainer; @@ -157,8 +174,8 @@ export class SwitcherComponent extends ComponentBase { resizerElement.style.minHeight = `${newHeight}px`; // Step 4: Clean up - let idOfCurrentAnimation = Math.random(); - this.idOfCurrentAnimation = idOfCurrentAnimation; + let idOfCurrentAnimation = this.idOfCurrentAnimation; + this.idOfCurrentAnimation++; // Clean up once the animation is finished setTimeout(() => { diff --git a/frontend/code/components/textInput.ts b/frontend/code/components/textInput.ts index b709057a..d8126acb 100644 --- a/frontend/code/components/textInput.ts +++ b/frontend/code/components/textInput.ts @@ -21,7 +21,7 @@ export class TextInputComponent extends ComponentBase { private onChangeLimiter: Debouncer; createElement(): HTMLElement { - this.inputBox = new InputBox(); + this.inputBox = new InputBox(this.id); let element = this.inputBox.outerElement; diff --git a/frontend/code/inputBox.ts b/frontend/code/inputBox.ts index 7873e722..d29c15ea 100644 --- a/frontend/code/inputBox.ts +++ b/frontend/code/inputBox.ts @@ -13,20 +13,23 @@ export class InputBox { private suffixTextElement: HTMLElement; private labelWidthReserverElement: HTMLElement; // Ensures enough width for the label - private labelElement: HTMLElement; + private labelElement: HTMLLabelElement; // NOTE: The input element can also be a textarea, but for some reason the // typing gets really wonky if this is a union. I don't like it, but I think // lying about the type is our best option. private _inputElement: HTMLInputElement; - constructor({ - inputElement, - labelIsAlwaysSmall, - }: { - inputElement?: HTMLInputElement | HTMLTextAreaElement; - labelIsAlwaysSmall?: boolean; - } = {}) { + constructor( + id: string | number, + { + inputElement, + labelIsAlwaysSmall, + }: { + inputElement?: HTMLInputElement | HTMLTextAreaElement; + labelIsAlwaysSmall?: boolean; + } = {} + ) { this.outerElement = document.createElement('div'); this.outerElement.classList.add('rio-input-box'); @@ -35,7 +38,7 @@ export class InputBox {