feat(react/dialog): port note_type_chooser

This commit is contained in:
Elian Doran
2025-08-06 11:39:31 +03:00
parent 2a40d6bb7e
commit 33e3112290
14 changed files with 238 additions and 214 deletions

View File

@@ -0,0 +1,44 @@
import { Dropdown as BootstrapDropdown } from "bootstrap";
import { ComponentChildren } from "preact";
import { useEffect, useRef } from "preact/hooks";
interface DropdownProps {
className?: string;
isStatic?: boolean;
children: ComponentChildren;
}
export default function Dropdown({ className, isStatic, children }: DropdownProps) {
const dropdownRef = useRef<HTMLDivElement>();
const triggerRef = useRef<HTMLButtonElement>();
if (triggerRef?.current) {
useEffect(() => {
const dropdown = BootstrapDropdown.getOrCreateInstance(triggerRef.current!);
return () => dropdown.dispose();
});
}
if (dropdownRef?.current) {
useEffect(() => {
$(dropdownRef.current!).on("hide.bs.dropdown", () => {
console.log("Hide");
});
});
}
return (
<div ref={dropdownRef} class="dropdown" style={{ display: "flex" }}>
<button
ref={triggerRef}
type="button"
style={{ display: "none" }}
data-bs-toggle="dropdown"
data-bs-display={ isStatic ? "static" : undefined } />
<div class={`dropdown-menu ${className ?? ""} ${isStatic ? "static" : undefined}`}>
{children}
</div>
</div>
)
}

View File

@@ -11,9 +11,11 @@ interface FormGroupProps {
export default function FormGroup({ label, title, className, children, description, labelRef }: FormGroupProps) {
return (
<div className={`form-group ${className}`} title={title}>
<div className={`form-group ${className}`} title={title}
style={{ "margin-bottom": "15px" }}>
<label style={{ width: "100%" }} ref={labelRef}>
{label} {children}
<div style={{ "margin-bottom": "10px" }}>{label}</div>
{children}
</label>
{description && <small className="form-text">{description}</small>}

View File

@@ -0,0 +1,49 @@
import { ComponentChildren } from "preact";
import Icon from "./Icon";
interface FormListOpts {
children: ComponentChildren;
onSelect?: (value: string) => void;
}
export default function FormList({ children, onSelect }: FormListOpts) {
return (
<div class="dropdown-menu static show" style={{
position: "relative"
}} onClick={(e) => {
const value = (e.target as HTMLElement)?.dataset?.value;
if (value && onSelect) {
onSelect(value);
}
}}>
{children}
</div>
);
}
interface FormListItemOpts {
text: string;
icon?: string;
value?: string;
}
export function FormListItem({ text, icon, value }: FormListItemOpts) {
return (
<a class="dropdown-item" data-value={value}>
<Icon icon={icon} />&nbsp;
{text}
</a>
);
}
interface FormListHeaderOpts {
text: string;
}
export function FormListHeader({ text }: FormListHeaderOpts) {
return (
<li>
<h6 className="dropdown-header">{text}</h6>
</li>
)
}

View File

@@ -0,0 +1,7 @@
interface IconProps {
icon?: string;
}
export default function Icon({ icon }: IconProps) {
return <span class={icon ?? "bx bx-empty"}></span>
}