import { string2Title } from "@maykin-ui/client-common"; import clsx from "clsx"; import React, { useId, useState } from "react"; import { Field, SerializedFormData, TypedField, fields2TypedFields, gettextFirst, } from "../../../lib"; import { Button } from "../../button"; import { Form, FormControl, FormProps } from "../../form"; import { Value } from "../value"; import "./attributetable.scss"; import { TRANSLATIONS } from "./translations"; export type AttributeTableProps = { /** The object. */ object?: T; // TODO: Deprecate? labeledObject?: Record; /** * Whether values should be made editable, default is determined by whether any of `fields` is a `TypedField` and has * `editable` set. */ editable?: boolean; /** A `string[]` or `TypedField[]` containing the keys in `objectList` to show value for. */ fields?: Field[] | TypedField[]; /** Props for Form. */ formProps?: FormProps>; /** The cancel label. */ labelCancel?: string; /** The edit value (accessible) label. */ labelEdit?: string; /** Vertical alignment of contents. */ valign?: "middle" | "start"; /** Whether a compact layout should be used. */ compact?: boolean; /** Whether wrapping should be allowed. */ wrap?: boolean; }; /** * AttributeTable Component * * Shows key/value pairs. * @see DataGrid for more advanced table layout. * * @typeParam T - The shape of a single item. */ export const AttributeTable = ({ object = {} as T, labeledObject = {}, editable = false, fields = Object.keys(object).concat(Object.keys(labeledObject)) as Field[], formProps, labelCancel, labelEdit, valign = "middle", compact = false, wrap = false, ...props }: AttributeTableProps) => { const [isFormOpenState, setIsFormOpenState] = useState(false); const typedFields = fields2TypedFields(fields, [object], { editable }); const _editable = Boolean(typedFields.find((f) => f.editable)); const _labelCancel = gettextFirst(labelCancel, TRANSLATIONS.LABEL_CANCEL); const renderTable = () => { return _editable ? ( > showRequiredExplanation={false} fieldsetClassName="mykn-attributetable__body" showActions={isFormOpenState} secondaryActions={[ { children: _labelCancel, variant: "secondary", onClick: () => setIsFormOpenState(false), }, ]} toolbarProps={{ overrideItemProps: true }} {...formProps} > {renderRows()} ) : (
{renderRows()}
); }; const renderRows = () => typedFields.map((field) => ( key={field.name.toString()} editable={_editable} field={field} isFormOpen={isFormOpenState} object={object} labeledObject={labeledObject} labelEdit={labelEdit} compact={compact} onClick={() => setIsFormOpenState(true)} /> )); return (
{renderTable()}
); }; export type AttributeTableRowProps = { editable?: boolean; object?: T; // TODO: Deprecate in favor of using TypedField for labels in the future? labeledObject?: Record; field: TypedField; isFormOpen: boolean; labelEdit?: string; onClick: React.MouseEventHandler; compact?: boolean; }; export const AttributeTableRow = ({ editable = false, field, isFormOpen, object = {} as T, labeledObject = {}, labelEdit, compact = false, onClick, }: AttributeTableRowProps) => { const id = useId(); const [isEditingState, setIsEditingState] = useState(false); const name = field.name; const fieldInObject = Object.keys(object).includes(name.toString()); const label = fieldInObject ? string2Title(name.toString()) : labeledObject[name as string].label; const rawValue = fieldInObject ? object[name as keyof T] : labeledObject[name as string].value; const isEditing = isFormOpen && isEditingState; const handleCLick: React.MouseEventHandler = (e) => { e.preventDefault(); setIsEditingState(true); onClick(e); }; const _labelEdit = gettextFirst(labelEdit, TRANSLATIONS.LABEL_EDIT, { ...field, label: label || field.name, }); const renderValue = () => { return editable ? ( ) : ( renderDisplayValue() ); }; const renderDisplayValue = () => { return ; }; const renderInput = () => { return (