mirror of
https://github.com/Novaloop-AG/healthchat-web.git
synced 2026-10-31 16:23:03 +00:00
11030ae68d
* Refactor DateSeparator using MVVM and move to shared-components
* Add a few more stories, tests and screenshots
* Use the shared component and viewmodel in element-web
* Renaming custom content property an updating snapshots
* Fix lint errors and update snapshot after merge
* Change lifecycle handling for DateSeparatoreViewModel in components where manual handling is preferrable over wrapper component.
* Move context menu from viewmodel to shared components - step 1
* Create a jump to date picker component in shared components
* Add tests for coverage and fix layout issues and roving indexes
* Make element-web use the new component
* Simplify context menu and adjusting tests
* The HTMLExport now render shared components and need a I18nContext.Provider
* Updating unit tests for context menu
* Changed to {translate: _t} to let scripts pick up translations
* Fix lint issue and updating screenshots after merge
* Update snaps for element web components
* Renaming MVVM view components with suffix View.
* Fixing problem with input date calendar icon and system dark theme
* Changed the rendering of the menu and added a separate button component
* Handle input control with useRef in onKeyDown
* Updating DateSeparator snapshots on unit tests
* Updating layout after compound Menu got a className property
* Move files to new subfolder after merge
* Updated snapshot after merge
* Updating lock file
* Updates to styling from PR review
* Updates to focus/blur functionality
* Fixed tabbing and export documentation to stories
* Updated snapshots
---------
Co-authored-by: Zack <zazi21@student.bth.se>
133 lines
4.5 KiB
TypeScript
133 lines
4.5 KiB
TypeScript
/*
|
|
* Copyright 2026 Element Creations Ltd.
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
* Please see LICENSE files in the repository root for full details.
|
|
*/
|
|
|
|
import React, { type JSX, useId, useRef, useState } from "react";
|
|
import { Root, Submit, Field, TextControl, MenuItem } from "@vector-im/compound-web";
|
|
|
|
import { formatDateForInput } from "../../utils/DateUtils";
|
|
import { useI18n } from "../../utils/i18nContext";
|
|
import { useViewModel } from "../../viewmodel";
|
|
import { type DateSeparatorViewModel } from "./DateSeparatorView";
|
|
import styles from "./DateSeparatorDatePickerView.module.css";
|
|
|
|
/**
|
|
* Props for DateSeparatorDatePickerView component.
|
|
*/
|
|
export interface DateSeparatorDatePickerViewProps {
|
|
/** The date separator view model. */
|
|
vm: DateSeparatorViewModel;
|
|
/** Optional input ref shared with parent for focus management. */
|
|
inputRef?: React.RefObject<HTMLInputElement | null>;
|
|
/** Called after a date has been submitted. */
|
|
onSubmitted?: () => void;
|
|
/** Called when the picker is dismissed without submitting. */
|
|
onDismissed?: () => void;
|
|
}
|
|
|
|
/**
|
|
* Date picker menu item.
|
|
*/
|
|
export const DateSeparatorDatePickerView: React.FC<DateSeparatorDatePickerViewProps> = ({
|
|
vm,
|
|
inputRef,
|
|
onSubmitted,
|
|
onDismissed,
|
|
}): JSX.Element => {
|
|
const snapshot = useViewModel(vm);
|
|
const date = snapshot.jumpFromDate ? new Date(snapshot.jumpFromDate) : new Date();
|
|
const dateInputDefaultValue = formatDateForInput(date);
|
|
|
|
const { translate: _t } = useI18n();
|
|
const dateInputId = useId();
|
|
const [dateValue, setDateValue] = useState(dateInputDefaultValue);
|
|
const localDateInputRef = useRef<HTMLInputElement>(null);
|
|
const dateInputRef = inputRef ?? localDateInputRef;
|
|
const submitButtonRef = useRef<HTMLButtonElement>(null);
|
|
|
|
const onDateInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {
|
|
if (event.key === "Tab") {
|
|
if (event.shiftKey) {
|
|
onDismissed?.();
|
|
} else {
|
|
event.preventDefault();
|
|
submitButtonRef.current?.focus();
|
|
}
|
|
}
|
|
};
|
|
|
|
const onDateValueInput = (event: React.InputEvent<HTMLInputElement>): void => {
|
|
setDateValue(event.currentTarget.value);
|
|
};
|
|
|
|
const submitDate = (): void => {
|
|
vm.onDatePicked?.(dateValue);
|
|
onSubmitted?.();
|
|
};
|
|
|
|
const onJumpToDateSubmit = (event: React.SubmitEvent<HTMLFormElement>): void => {
|
|
event.preventDefault();
|
|
submitDate();
|
|
};
|
|
|
|
const onSubmitButtonKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>): void => {
|
|
if (event.key === "Tab") {
|
|
if (event.shiftKey) {
|
|
event.preventDefault();
|
|
dateInputRef.current?.focus();
|
|
} else {
|
|
onDismissed?.();
|
|
}
|
|
}
|
|
|
|
if (event.key == "Enter" || event.key == " " || event.key == "Spacebar") {
|
|
event.preventDefault();
|
|
submitDate();
|
|
}
|
|
};
|
|
|
|
const keepMenuOpenOnSelect = (event: Event): void => {
|
|
event.preventDefault();
|
|
};
|
|
|
|
return (
|
|
<MenuItem
|
|
as="div"
|
|
data-testid="jump-to-date-picker"
|
|
label={_t("room|jump_to_date")}
|
|
onSelect={keepMenuOpenOnSelect}
|
|
hideChevron={true}
|
|
className={styles.picker_menu_item}
|
|
>
|
|
<Root className={styles.picker_form} onSubmit={onJumpToDateSubmit}>
|
|
<Field name="jump-to-date-field" className={styles.picker_input}>
|
|
<TextControl
|
|
ref={dateInputRef}
|
|
id={dateInputId}
|
|
type="date"
|
|
aria-label={_t("room|jump_to_date_prompt")}
|
|
onInput={onDateValueInput}
|
|
onKeyDown={onDateInputKeyDown}
|
|
value={dateValue}
|
|
max={formatDateForInput(new Date())}
|
|
className={styles.picker_input_date}
|
|
/>
|
|
</Field>
|
|
<Submit
|
|
ref={submitButtonRef}
|
|
className={styles.picker_button}
|
|
type="submit"
|
|
kind="primary"
|
|
size="sm"
|
|
onKeyDown={onSubmitButtonKeyDown}
|
|
>
|
|
{_t("action|go")}
|
|
</Submit>
|
|
</Root>
|
|
</MenuItem>
|
|
);
|
|
};
|