Skip to content

Commit

Permalink
🐛 - fix: various issues while implementing library
Browse files Browse the repository at this point in the history
  • Loading branch information
svenvandescheur committed Apr 8, 2024
1 parent e6bd9bf commit 008fcb9
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 79 deletions.
3 changes: 1 addition & 2 deletions src/components/data/datagrid/datagrid.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
}

&__caption {
padding: var(--spacing-v) var(--spacing-h);
text-align: start;
}

Expand Down Expand Up @@ -70,7 +69,7 @@
top: 50%;
transform: translate(-50%, -50%);
width: 100%;
z-index: 1;
z-index: 1000;

.mykn-input {
width: 100%;
Expand Down
94 changes: 56 additions & 38 deletions src/components/data/datagrid/datagrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
SerializedFormData,
TypedField,
formatMessage,
isPrimitive,
serializeForm,
typedFieldByFields,
useIntl,
Expand Down Expand Up @@ -110,6 +109,9 @@ export type DataGridProps = {
attributeData: DataGridProps["objectList"][number],
) => void;

/** Gets called when a row value is edited. */
onChange?: (event: React.ChangeEvent) => void;

/** Gets called when a row value is edited. */
onEdit?: (rowData: SerializedFormData) => void;

Expand Down Expand Up @@ -148,10 +150,11 @@ const getRenderableFields = (
fields: Array<Field | TypedField>,
objectList: AttributeData[],
urlFields: string[],
editable: DataGridProps["editable"],
): TypedField[] =>
typedFieldByFields(fields, objectList).filter(
(f) => !urlFields.includes(String(f.name)),
);
typedFieldByFields(fields, objectList, {
editable: Boolean(editable),
}).filter((f) => !urlFields.includes(String(f.name)));

/**
* A subset of `PaginatorProps` that act as aliases.
Expand All @@ -176,7 +179,7 @@ export const DataGrid: React.FC<DataGridProps> = ({
boolProps,
objectList,
fields = objectList?.length ? Object.keys(objectList[0]) : [],
editable = Boolean(fields.find((f) => !isPrimitive(f) && f.editable)),
editable = undefined,
paginatorProps,
showPaginator = Boolean(paginatorProps),
pProps,
Expand All @@ -187,6 +190,7 @@ export const DataGrid: React.FC<DataGridProps> = ({
urlFields = DEFAULT_URL_FIELDS,
labelSelect,
labelSelectAll,
onChange,
onEdit,
onSelect,
onSelectionChange,
Expand Down Expand Up @@ -214,12 +218,6 @@ export const DataGrid: React.FC<DataGridProps> = ({
[string, "ASC" | "DESC"] | undefined
>();

// Trigger onSelectionChange when selectedState changes.
useEffect(() => {
const dirty = selectedState && selected !== selectedState;
dirty && onSelectionChange?.(selectedState as AttributeData[]);
}, [selectedState]);

// Update selectedState when selected prop changes.
useEffect(() => {
selected && setSelectedState(selected);
Expand All @@ -232,7 +230,12 @@ export const DataGrid: React.FC<DataGridProps> = ({
}
}, [sort]);

const renderableFields = getRenderableFields(fields, objectList, urlFields);
const renderableFields = getRenderableFields(
fields,
objectList,
urlFields,
editable,
);
const sortField = sortState?.[0];
const sortDirection = sortState?.[1];
const titleId = title ? `${id}-caption` : undefined;
Expand All @@ -253,20 +256,22 @@ export const DataGrid: React.FC<DataGridProps> = ({
const value = allSelected ? [] : renderableRows;
setSelectedState(value);
onSelect?.(value, !allSelected);
onSelectionChange?.(value);
};

const handleSelect = (attributeData: AttributeData) => {
const currentlySelected = selectedState || [];

const isAttributeDataCurrentlySelected =
currentlySelected.includes(attributeData);

setSelectedState(
isAttributeDataCurrentlySelected
? [...currentlySelected].filter((a) => a !== attributeData)
: [...currentlySelected, attributeData],
);
const newSelectedState = isAttributeDataCurrentlySelected
? [...currentlySelected].filter((a) => a !== attributeData)
: [...currentlySelected, attributeData];

setSelectedState(newSelectedState);
onSelect?.([attributeData], !isAttributeDataCurrentlySelected);
onSelectionChange?.(newSelectedState);
};

/**
Expand Down Expand Up @@ -337,20 +342,20 @@ export const DataGrid: React.FC<DataGridProps> = ({
amountSelected={selectedState?.length || 0}
count={count || 0}
dataGridId={id}
editable={editable}
editable={Boolean(renderableFields.find((f) => f.editable))}
editingRow={editingState[0]}
editingFieldIndex={editingState[1]}
fields={fields}
handleSelect={handleSelect}
labelSelect={labelSelect || ""}
onChange={onChange}
onClick={onClick}
onEdit={onEdit}
page={page || 1}
renderableFields={renderableFields}
renderableRows={renderableRows}
setEditingState={setEditingState}
selectable={selectable}
selectedRows={selected || []}
selectedRows={selectedState || []}
sortDirection={sortDirection}
sortField={sortField}
urlFields={urlFields}
Expand Down Expand Up @@ -458,9 +463,9 @@ export type DataGridBodyProps = {
editable: boolean;
editingRow: AttributeData | null;
editingFieldIndex: number | null;
fields: Array<Field | TypedField>;
handleSelect: (attributeData: AttributeData) => void;
labelSelect: string;
onChange: DataGridProps["onChange"];
onClick: DataGridProps["onClick"];
onEdit: DataGridProps["onEdit"];
page: number;
Expand Down Expand Up @@ -488,9 +493,9 @@ export const DataGridBody: React.FC<DataGridBodyProps> = ({
editable,
editingRow,
editingFieldIndex,
fields,
handleSelect,
labelSelect,
onChange,
onClick,
onEdit,
page,
Expand Down Expand Up @@ -545,8 +550,9 @@ export const DataGridBody: React.FC<DataGridBodyProps> = ({
editingFieldIndex === renderableFields.indexOf(field)
}
field={field}
fields={fields}
renderableFields={renderableFields}
urlFields={urlFields}
onChange={onChange}
onClick={(e, rowData) => {
if (editable) {
setEditingState([rowData, renderableFields.indexOf(field)]);
Expand Down Expand Up @@ -675,8 +681,9 @@ export type DataGridContentCellProps = {
dataGridId: string;
rowData: AttributeData;
field: TypedField;
fields: DataGridProps["fields"];
renderableFields: TypedField[];
urlFields: DataGridProps["urlFields"];
onChange: DataGridProps["onChange"];
onClick: DataGridProps["onClick"];
onEdit: DataGridProps["onEdit"];
};
Expand All @@ -694,17 +701,17 @@ export const DataGridContentCell: React.FC<DataGridContentCellProps> = ({
isEditingRow,
isEditingField,
field,
fields = [],
renderableFields = [],
rowData,
urlFields = DEFAULT_URL_FIELDS,
onChange,
onClick,
onEdit,
}) => {
const [pristine, setPristine] = useState<boolean>(true);

const fieldEditable =
typeof field.editable === "boolean" ? field.editable : editable;
const renderableFields = getRenderableFields(fields, [rowData], urlFields);
const fieldIndex = renderableFields.findIndex((f) => f.name === field.name);
const urlField = urlFields.find((f) => rowData[f]);
const rowUrl = urlField ? rowData[urlField] : null;
Expand Down Expand Up @@ -753,9 +760,15 @@ export const DataGridContentCell: React.FC<DataGridContentCellProps> = ({
value={(value || "").toString()}
form={`${dataGridId}-editable-form`}
required={true}
onChange={() => setPristine(false)}
onChange={(e: React.ChangeEvent) => {
setPristine(false);
onChange?.(e);
}}
onBlur={(e: React.FocusEvent<HTMLInputElement | HTMLSelectElement>) => {
const data = serializeForm(e.target.form as HTMLFormElement, true);
const data = Object.assign(
rowData,
serializeForm(e.target.form as HTMLFormElement, true),
);
!pristine && onEdit?.(data);
}}
/>
Expand Down Expand Up @@ -784,15 +797,20 @@ export const DataGridContentCell: React.FC<DataGridContentCellProps> = ({
/**
* Renders the value according to Value component
*/
const renderValue = () => (
<Value
aProps={aProps}
badgeProps={badgeProps}
boolProps={boolProps as BoolProps}
pProps={pProps}
value={value}
/>
);
const renderValue = () => {
// Support label from select
const label = field.options?.find((o) => o.value === value)?.label;

return (
<Value
aProps={aProps}
badgeProps={badgeProps}
boolProps={boolProps as BoolProps}
pProps={pProps}
value={label || value}
/>
);
};

return (
<td
Expand All @@ -807,12 +825,12 @@ export const DataGridContentCell: React.FC<DataGridContentCellProps> = ({
)}
aria-description={field2Caption(field.name)}
>
{isEditingRow && !isEditingField && renderHiddenInput()}
{link && (
<A href={link} aria-label={link} onClick={(e) => onClick?.(e, rowData)}>
<Outline.ArrowTopRightOnSquareIcon />
</A>
)}
{isEditingRow && !isEditingField && renderHiddenInput()}
{isEditingField && renderFormControl()}
{!isEditingField && fieldEditable && renderButton()}
{!isEditingField && !fieldEditable && renderValue()}
Expand Down
8 changes: 7 additions & 1 deletion src/components/form/form/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { forceArray } from "../../../lib/format/array";
import { ucFirst } from "../../../lib/format/string";
import { useIntl } from "../../../lib/i18n/useIntl";
import { Button } from "../../button";
import { Toolbar, ToolbarItem } from "../../toolbar";
import { Toolbar, ToolbarItem, ToolbarProps } from "../../toolbar";
import { ErrorMessage } from "../errormessage";
import { FormControl } from "../formcontrol";
import { InputProps } from "../input";
Expand Down Expand Up @@ -51,6 +51,9 @@ export type FormProps = React.ComponentProps<"form"> & {
/** Whether to show the form actions. */
showActions?: boolean;

/** Props to pass to Toolbar. */
toolbarProps?: Partial<ToolbarProps>;

/** The submit form label. */
labelSubmit?: string;

Expand Down Expand Up @@ -90,6 +93,7 @@ export type FormProps = React.ComponentProps<"form"> & {
* @param onChange
* @param onSubmit
* @param showActions
* @param toolbarProps
* @param useTypedResults
* @param validate
* @param validateOnChange
Expand All @@ -110,6 +114,7 @@ export const Form: React.FC<FormProps> = ({
onChange,
onSubmit,
showActions = true,
toolbarProps,
useTypedResults = false,
validate,
validateOnChange = false,
Expand Down Expand Up @@ -237,6 +242,7 @@ export const Form: React.FC<FormProps> = ({
align={secondaryActions.length ? "space-between" : "end"}
variant={"transparent"}
items={secondaryActions}
{...toolbarProps}
>
<Button
type="submit"
Expand Down
4 changes: 2 additions & 2 deletions src/components/form/select/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -359,9 +359,9 @@ const BaseSelectDropdown: React.FC<SelectDropdownProps> = ({
* Renders the `SelectOption` components
*/
const renderOptions = () =>
options.map(({ label }, i) => (
options.map(({ label, value }, i) => (
<SelectOption
key={label}
key={`${label}-${value || label}`}
ref={(node) => {
listRef.current[i] = node;
}}
Expand Down
8 changes: 7 additions & 1 deletion src/components/toolbar/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export type ToolbarProps = React.PropsWithChildren<
/** Aligns the contents based on the current direction. */
align?: "start" | "center" | "end" | "space-between";

/** The position of `children` compared to `items`. */
childrenPosition?: "before" | "after";

/** Whether the toolbar shows items horizontally or vertically, mobile devices always use vertical. */
direction?: "horizontal" | "vertical";

Expand Down Expand Up @@ -44,6 +47,7 @@ export type ToolbarProps = React.PropsWithChildren<
* A flexible and customizable toolbar component for arranging and aligning
* various interactive elements such as `A`, `Button`, `ButtonLink` and `Dropdown`.
* @param children
* @param childrenPosition
* @param align
* @param compact
* @param direction
Expand All @@ -57,6 +61,7 @@ export type ToolbarProps = React.PropsWithChildren<
*/
export const Toolbar: React.FC<ToolbarProps> = ({
children,
childrenPosition = "after",
align = "start",
compact = false,
direction = "horizontal",
Expand Down Expand Up @@ -128,8 +133,9 @@ export const Toolbar: React.FC<ToolbarProps> = ({
role="toolbar"
{...props}
>
{childrenPosition === "before" && children}
{items.map(renderItem)}
{children}
{childrenPosition === "after" && children}
</nav>
);
};
22 changes: 13 additions & 9 deletions src/lib/data/attributedata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,20 +123,24 @@ export const fieldsByTypedFields = (
* Converts `Array<Field , TypedField>` to `TypedField[]` by inspecting `attributeDataArray`.
* @param optionallyTypedFields
* @param attributeDataArray
* @param base
*/
export const typedFieldByFields = (
optionallyTypedFields: Array<Field | TypedField>,
attributeDataArray: AttributeData[],
): TypedField[] => {
return optionallyTypedFields.map((field) =>
isPrimitive<Field>(field)
? {
type: typeByAttributeDataArray(field, attributeDataArray),
name: field,
}
: field,
base?: Partial<TypedField>,
): TypedField[] =>
optionallyTypedFields.map((field) =>
Object.assign(
{ ...base } || {},
isPrimitive<Field>(field)
? {
type: typeByAttributeDataArray(field, attributeDataArray),
name: field,
}
: field,
),
);
};

/**
* Attempts to find `field`'s type based on its presence in a row in `attributeDataArray`.
Expand Down
Loading

0 comments on commit 008fcb9

Please sign in to comment.