feat(react/dialogs): port note revisions

This commit is contained in:
Elian Doran
2025-08-06 16:16:30 +03:00
parent f7e7b38551
commit 7ac0828ae7
6 changed files with 200 additions and 391 deletions

View File

@@ -1,4 +1,5 @@
import { RefObject } from "preact";
import { CSSProperties } from "preact/compat";
import { useRef } from "preact/hooks";
interface ButtonProps {
@@ -12,9 +13,11 @@ interface ButtonProps {
onClick?: () => void;
primary?: boolean;
disabled?: boolean;
small?: boolean;
style?: CSSProperties;
}
export default function Button({ buttonRef: _buttonRef, className, text, onClick, keyboardShortcut, icon, primary, disabled }: ButtonProps) {
export default function Button({ buttonRef: _buttonRef, className, text, onClick, keyboardShortcut, icon, primary, disabled, small, style }: ButtonProps) {
const classes: string[] = ["btn"];
if (primary) {
classes.push("btn-primary");
@@ -24,6 +27,9 @@ export default function Button({ buttonRef: _buttonRef, className, text, onClick
if (className) {
classes.push(className);
}
if (small) {
classes.push("btn-sm");
}
const buttonRef = _buttonRef ?? useRef<HTMLButtonElement>(null);
const splitShortcut = (keyboardShortcut ?? "").split("+");
@@ -35,6 +41,7 @@ export default function Button({ buttonRef: _buttonRef, className, text, onClick
onClick={onClick}
ref={buttonRef}
disabled={disabled}
style={style}
>
{icon && <span className={`bx ${icon}`}></span>}
{text} {keyboardShortcut && (

View File

@@ -1,15 +1,18 @@
import { ComponentChildren } from "preact";
import Icon from "./Icon";
import { CSSProperties } from "preact/compat";
interface FormListOpts {
children: ComponentChildren;
onSelect?: (value: string) => void;
style?: CSSProperties;
}
export default function FormList({ children, onSelect }: FormListOpts) {
export default function FormList({ children, onSelect, style }: FormListOpts) {
return (
<div class="dropdown-menu static show" style={{
position: "relative"
...style ?? {},
position: "relative",
}} onClick={(e) => {
const value = (e.target as HTMLElement)?.dataset?.value;
if (value && onSelect) {
@@ -25,11 +28,12 @@ interface FormListItemOpts {
children: ComponentChildren;
icon?: string;
value?: string;
title?: string;
}
export function FormListItem({ children, icon, value }: FormListItemOpts) {
export function FormListItem({ children, icon, value, title }: FormListItemOpts) {
return (
<a class="dropdown-item" data-value={value}>
<a class="dropdown-item" data-value={value} title={title}>
<Icon icon={icon} />&nbsp;
{children}
</a>

View File

@@ -8,6 +8,10 @@ interface ModalProps {
title: string | ComponentChildren;
size: "xl" | "lg" | "md" | "sm";
children: ComponentChildren;
/**
* Items to display in the modal header, apart from the title itself which is handled separately.
*/
header?: ComponentChildren;
footer?: ComponentChildren;
footerAlignment?: "right" | "between";
minWidth?: string;
@@ -39,9 +43,10 @@ interface ModalProps {
* Gives access to the underlying form element of the modal. This is only set if `onSubmit` is provided.
*/
formRef?: RefObject<HTMLFormElement>;
bodyStyle?: CSSProperties;
}
export default function Modal({ children, className, size, title, footer, footerAlignment, onShown, onSubmit, helpPageId, minWidth, maxWidth, zIndex, scrollable, onHidden: onHidden, modalRef: _modalRef, formRef: _formRef }: ModalProps) {
export default function Modal({ children, className, size, title, header, footer, footerAlignment, onShown, onSubmit, helpPageId, minWidth, maxWidth, zIndex, scrollable, onHidden: onHidden, modalRef: _modalRef, formRef: _formRef, bodyStyle }: ModalProps) {
const modalRef = _modalRef ?? useRef<HTMLDivElement>(null);
const formRef = _formRef ?? useRef<HTMLFormElement>(null);
@@ -91,6 +96,7 @@ export default function Modal({ children, className, size, title, footer, footer
) : (
title
)}
{header}
{helpPageId && (
<button className="help-button" type="button" data-in-app-help={helpPageId} title={t("modal.help_title")}>?</button>
)}
@@ -102,10 +108,10 @@ export default function Modal({ children, className, size, title, footer, footer
e.preventDefault();
onSubmit();
}}>
<ModalInner footer={footer}>{children}</ModalInner>
<ModalInner footer={footer} bodyStyle={bodyStyle}>{children}</ModalInner>
</form>
) : (
<ModalInner footer={footer}>
<ModalInner footer={footer} bodyStyle={bodyStyle}>
{children}
</ModalInner>
)}
@@ -115,7 +121,7 @@ export default function Modal({ children, className, size, title, footer, footer
);
}
function ModalInner({ children, footer, footerAlignment }: Pick<ModalProps, "children" | "footer" | "footerAlignment">) {
function ModalInner({ children, footer, footerAlignment, bodyStyle }: Pick<ModalProps, "children" | "footer" | "footerAlignment" | "bodyStyle">) {
const footerStyle: CSSProperties = {};
if (footerAlignment === "between") {
footerStyle.justifyContent = "space-between";
@@ -123,7 +129,7 @@ function ModalInner({ children, footer, footerAlignment }: Pick<ModalProps, "chi
return (
<>
<div className="modal-body">
<div className="modal-body" style={bodyStyle}>
{children}
</div>