Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/list template #38

Merged
merged 9 commits into from
Feb 27, 2024
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
],
"exports": {
".": "./dist/esm/index.js",
"./components": "./dist/esm/componets/index.js",
"./components": "./dist/esm/components/index.js",
"./contexts": "./dist/esm/contexts/index.js",
"./lib": "./dist/esm/lib/index.js",
"./templates": "./dist/esm/templates/index.js",
"./style": "./dist/esm/index.css"
},
Expand Down
2 changes: 1 addition & 1 deletion rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import json from "@rollup/plugin-json";
export default [
{
external: ["@floating-ui/react", "@heroicons/react/24/outline", "@heroicons/react/24/solid", "clsx"],
input: "src/index.tsx",
input: "src/index.ts",
output: [{
assetFileNames: "[name][extname]",
dir: "dist/cjs",
Expand Down
4 changes: 1 addition & 3 deletions src/components/data/datagrid/datagrid.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,7 @@ export const JSONPlaceholderExample: Story = {
render: (args) => {
const [loading, setLoading] = useState(false);
const [page, setPage] = useState<number>(args.paginatorProps?.page || 1);
const [pageSize, setPageSize] = useState<number>(
args.paginatorProps?.pageSize || 10,
);
const [pageSize, setPageSize] = useState<number>(args.pageSize || 10);
const [results, setResults] = useState<AttributeData[]>([]);
const [sort, setSort] = useState<string>("");

Expand Down
23 changes: 20 additions & 3 deletions src/components/data/datagrid/datagrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ export type DataGridProps = {
/** A title for the datagrid. */
title?: string;

/** Gets called when a result is selected. */
onClick?: (
event: React.MouseEvent<HTMLAnchorElement>,
attributeData: DataGridProps["results"][number],
) => void;

/** Gets called when the results are sorted. */
onSort?: (sort: string) => Promise<unknown> | void;
} & PaginatorPropsAliases;

Expand Down Expand Up @@ -108,6 +115,7 @@ type PaginatorPropsAliases = {
* @param page
* @param pageSize
* @param pageSizeOptions
* @param onClick
* @param onPageChange
* @param onPageSizeChange
* @param props
Expand All @@ -132,6 +140,7 @@ export const DataGrid: React.FC<DataGridProps> = ({
page,
pageSize,
pageSizeOptions,
onClick,
onPageChange,
onPageSizeChange,
...props
Expand All @@ -155,7 +164,7 @@ export const DataGrid: React.FC<DataGridProps> = ({
const sortedResults =
!onSort && sortField && sortDirection
? sortAttributeDataArray(results, sortField, sortDirection)
: results;
: results || [];

/**
* Get called when a column is sorted.
Expand Down Expand Up @@ -205,6 +214,7 @@ export const DataGrid: React.FC<DataGridProps> = ({
field={field}
fields={fields}
urlFields={urlFields}
onClick={onClick}
/>
);
};
Expand Down Expand Up @@ -326,6 +336,7 @@ export type DataGridCellProps = {
field: string;
fields: DataGridProps["fields"];
urlFields: DataGridProps["urlFields"];
onClick: DataGridProps["onClick"];
};

/**
Expand All @@ -338,6 +349,7 @@ export type DataGridCellProps = {
* @param fields
* @param rowData
* @param urlFields
* @param onClick
* @constructor
* @private
*/
Expand All @@ -350,10 +362,11 @@ export const DataGridCell: React.FC<DataGridCellProps> = ({
fields = [],
rowData,
urlFields = DEFAULT_URL_FIELDS,
onClick,
}) => {
const renderableFields = fields.filter((f) => !urlFields.includes(f));
const fieldIndex = renderableFields.indexOf(field);
const urlField = urlFields.find((f) => isLink(String(rowData[f])));
const urlField = urlFields.find((f) => rowData[f]);
const rowUrl = urlField ? rowData[urlField] : null;
const value = rowData[field];
const type = isNull(value) ? "null" : typeof value;
Expand All @@ -370,7 +383,11 @@ export const DataGridCell: React.FC<DataGridCellProps> = ({
aria-description={field2Caption(field as string)}
>
{link && (
<A href={link} aria-label={link}>
<A
href={link}
aria-label={link}
onClick={(e) => onClick && onClick(e, rowData)}
>
<Outline.ArrowTopRightOnSquareIcon />
</A>
)}
Expand Down
6 changes: 3 additions & 3 deletions src/components/form/errormessage/errormessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";

import "./errormessage.scss";

export type ErrorMessageProps = React.ComponentProps<"span">;
export type ErrorMessageProps = React.ComponentProps<"div">;

/**
* ErrorMessage component
Expand All @@ -14,7 +14,7 @@ export const ErrorMessage: React.FC<ErrorMessageProps> = ({
children,
...props
}) => (
<span className="mykn-errormessage" role={"alert"} {...props}>
<div className="mykn-errormessage" role={"alert"} {...props}>
{children}
</span>
</div>
);
16 changes: 16 additions & 0 deletions src/components/form/form/form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@
gap: var(--spacing-v-l);
width: 100%;

&__fieldset {
display: flex;
flex-direction: column;
gap: var(--spacing-v-l);
width: 100%;
}

&--direction-horizontal {
width: auto;
}

&--direction-horizontal &__fieldset, {
flex-direction: row;
width: auto;
}

.mykn-toolbar .mykn-button {
justify-content: center;
}
Expand Down
79 changes: 52 additions & 27 deletions src/components/form/form/form.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import clsx from "clsx";
import React, {
ChangeEventHandler,
FormEvent,
useContext,
useEffect,
useState,
} from "react";

import { ConfigContext } from "../../../contexts";
import { Attribute, AttributeData } from "../../../lib/data/attributedata";
import { FormField } from "../../../lib/form/typeguards";
import {
Expand All @@ -27,6 +30,9 @@ export type FormProps = React.ComponentProps<"form"> & {
/** If set, show `valuesState`. */
debug?: boolean;

/** The direction in which to render the form. */
direction?: "vertical" | "horizontal";

/** The initial form values, only applies on initial render. */
initialValues?: AttributeData<Attribute | Attribute[]>;

Expand Down Expand Up @@ -71,6 +77,7 @@ export type FormProps = React.ComponentProps<"form"> & {
* Generic form component, capable of auto rendering `fields` based on their shape.
* @param children
* @param debug
* @param direction
* @param errors
* @param fields
* @param initialValues
Expand All @@ -89,6 +96,7 @@ export type FormProps = React.ComponentProps<"form"> & {
export const Form: React.FC<FormProps> = ({
children,
debug = false,
direction = "vertical",
errors,
fields = [],
initialValues = {},
Expand All @@ -103,6 +111,10 @@ export const Form: React.FC<FormProps> = ({
values,
...props
}) => {
const { debug: contextDebug } = useContext(ConfigContext);
const _debug = debug || contextDebug;
const _nonFieldErrors = forceArray(nonFieldErrors);

const [valuesState, setValuesState] = useState(initialValues);
useEffect(() => values && setValuesState(values), [values]);
const [errorsState, setErrorsState] = useState(errors || {});
Expand Down Expand Up @@ -174,33 +186,46 @@ export const Form: React.FC<FormProps> = ({
};

return (
<form className="mykn-form" onSubmit={defaultOnSubmit} {...props}>
{forceArray(nonFieldErrors)?.map((error) => (
<ErrorMessage key={error}>{error}</ErrorMessage>
))}

{fields.map((field, index) => {
const value =
(field.value as string) ||
getValueFromFormData(fields, valuesState, field);

const error = getErrorFromErrors(fields, errorsState, field);
const change = defaultOnChange;

return (
<FormControl
key={field.id || index}
error={error}
value={value}
onChange={change as ChangeEventHandler}
{...field}
></FormControl>
);
})}

{children}

{debug && <pre role="log">{JSON.stringify(valuesState)}</pre>}
<form
className={clsx("mykn-form", `mykn-form--direction-${direction}`)}
onSubmit={defaultOnSubmit}
{...props}
>
{_nonFieldErrors?.length && (
<div className="mykn-form__non-field-errors">
{_nonFieldErrors?.map((error) => (
<ErrorMessage key={error}>{error}</ErrorMessage>
))}
</div>
)}

{Boolean(fields?.length) && (
<div className="mykn-form__fieldset">
{fields.map((field, index) => {
const value =
(field.value as string) ||
getValueFromFormData(fields, valuesState, field);

const error = getErrorFromErrors(fields, errorsState, field);
const change = defaultOnChange;

return (
<FormControl
key={field.id || index}
direction={direction}
error={error}
value={value}
onChange={change as ChangeEventHandler}
{...field}
></FormControl>
);
})}
</div>
)}

{children && <div className="mykn-form__fieldset">{children}</div>}

{_debug && <pre role="log">{JSON.stringify(valuesState)}</pre>}

{showActions && (
<Toolbar
Expand Down
6 changes: 6 additions & 0 deletions src/components/form/formcontrol/formcontrol.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,10 @@
.mykn-select {
width: 100%;
}

&--direction-horizontal {
align-items: center;
flex-direction: row;
white-space: nowrap;
}
}
18 changes: 16 additions & 2 deletions src/components/form/formcontrol/formcontrol.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import clsx from "clsx";
import React, { useId } from "react";

import { FormField, isInput, isSelect } from "../../../lib/form/typeguards";
Expand All @@ -7,16 +8,24 @@ import { Label } from "../label";
import { Select } from "../select";
import "./formcontrol.scss";

export type FormControlProps = FormField & { error?: string };
export type FormControlProps = FormField & {
/** The direction in which to render the form. */
direction?: "vertical" | "horizontal";

/** An error message to show. */
error?: string;
};

/**
* Renders the correct form widget (based on its props shape) along with its
* label and `error` message.
* @param direction
* @param error
* @param props
* @constructor
*/
export const FormControl: React.FC<FormControlProps> = ({
direction = "vertical",
error = "",
...props
}) => {
Expand All @@ -25,7 +34,12 @@ export const FormControl: React.FC<FormControlProps> = ({
const idError = `${id}_error`;

return (
<div className="mykn-form-control">
<div
className={clsx(
"mykn-form-control",
`mykn-form-control--direction-${direction}`,
)}
>
{props.label && <Label htmlFor={_id}>{props.label}</Label>}
<FormWidget
id={_id}
Expand Down
1 change: 0 additions & 1 deletion src/components/form/input/input.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,6 @@ export const UsageWithFormik: Story = {
type: "text",
},
argTypes: {
// @ts-expect-error - Using FormikProps here while SelectProps is expected.
validate: { action: "validate" },
onSubmit: { action: "onSubmit" },
},
Expand Down
1 change: 1 addition & 0 deletions src/components/form/select/select.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
min-height: 38px;
max-width: 100%;
position: relative;
text-align: start;

&--size-fit-content {
width: fit-content;
Expand Down
8 changes: 6 additions & 2 deletions src/components/layout/column/column.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import clsx from "clsx";
import React from "react";
import React, { useContext } from "react";

import { ConfigContext } from "../../../contexts";
import "./column.scss";

export type ColumnProps = React.PropsWithChildren<{
Expand Down Expand Up @@ -33,10 +34,13 @@ export const Column: React.FC<ColumnProps> = ({
start,
...props
}) => {
const { debug: contextDebug } = useContext(ConfigContext);
const _debug = debug || contextDebug;

return (
<div
className={clsx("mykn-column", `mykn-column--span-${span}`, {
"mykn-column--debug": debug,
"mykn-column--debug": _debug,
[`mykn-column--start-${start}`]: start,
})}
{...props}
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/container/container.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
container-name: container;
container-type: inline-size;
margin: 0 auto;
max-width: 1240px;
max-width: var(--page-container-size);
width: 100%;

&--debug {
Expand Down
Loading
Loading